2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1998-2009 Oracle. All rights reserved.
6 * This code is derived from software contributed to Sleepycat Software by
7 * Frederick G.M. Roeber of Netscape Communications Corp.
12 #include "db_config.h"
17 * DB uses memory-mapped files for two things:
18 * faster access of read-only databases, and
19 * shared memory for process synchronization and locking.
20 * The code carefully does not mix the two uses. The first-case uses are
21 * actually written such that memory-mapping isn't really required -- it's
22 * merely a convenience -- so we don't have to worry much about it. In the
23 * second case, it's solely used as a shared memory mechanism, so that's
24 * all we have to replace.
26 * All memory in VxWorks is shared, and a task can allocate memory and keep
27 * notes. So I merely have to allocate memory, remember the "filename" for
28 * that memory, and issue small-integer segment IDs which index the list of
29 * these shared-memory segments. Subsequent opens are checked against the
30 * list of already open segments.
33 void *segment; /* Segment address. */
34 u_int32_t size; /* Segment size. */
35 char *name; /* Segment name. */
36 long segid; /* Segment ID. */
39 static os_segdata_t *__os_segdata; /* Segment table. */
40 static int __os_segdata_size; /* Segment table size. */
42 #define OS_SEGDATA_STARTING_SIZE 16
43 #define OS_SEGDATA_INCREMENT 16
45 static int __os_segdata_allocate
46 __P((ENV *, const char *, REGINFO *, REGION *));
47 static int __os_segdata_find_byname
48 __P((ENV *, const char *, REGINFO *, REGION *));
49 static int __os_segdata_init __P((ENV *));
50 static int __os_segdata_new __P((ENV *, int *));
51 static int __os_segdata_release __P((ENV *, REGION *, int));
55 * Create/join a shared memory region.
58 __os_attach(env, infop, rp)
68 if (__os_segdata == NULL)
69 __os_segdata_init(env);
71 DB_BEGIN_SINGLE_THREAD;
73 /* Try to find an already existing segment. */
74 ret = __os_segdata_find_byname(env, infop->name, infop, rp);
77 * If we are trying to join a region, it is easy, either we
78 * found it and we return, or we didn't find it and we return
79 * an error that it doesn't exist.
81 if (!F_ISSET(infop, REGION_CREATE)) {
83 __db_errx(env, "segment %s does not exist",
91 * If we get here, we are trying to create the region.
92 * There are several things to consider:
93 * - if we have an error (not a found or not-found value), return.
94 * - they better have shm_key set.
95 * - if the region is already there (ret == 0 from above),
96 * assume the application crashed and we're restarting.
97 * Delete the old region.
98 * - try to create the region.
100 if (ret != 0 && ret != ENOENT)
103 if (dbenv->shm_key == INVALID_REGION_SEGID) {
104 __db_errx(env, "no base shared memory ID specified");
108 if (ret == 0 && __os_segdata_release(env, rp, 1) != 0) {
110 "key: %ld: shared memory region already exists",
111 dbenv->shm_key + (infop->id - 1));
116 ret = __os_segdata_allocate(env, infop->name, infop, rp);
118 DB_END_SINGLE_THREAD;
124 * Detach from a shared region.
127 __os_detach(env, infop, destroy)
133 * If just detaching, there is no mapping to discard.
134 * If destroying, remove the region.
137 return (__os_segdata_release(env, infop->rp, 0));
143 * Map in a shared memory file.
146 __os_mapfile(env, path, fhp, len, is_rdonly, addrp)
154 /* We cannot map in regular files in VxWorks. */
155 COMPQUIET(env, NULL);
156 COMPQUIET(path, NULL);
157 COMPQUIET(fhp, NULL);
158 COMPQUIET(is_rdonly, 0);
160 COMPQUIET(addrp, NULL);
161 return (DB_OPNOTSUP);
166 * Unmap the shared memory file.
169 __os_unmapfile(env, addr, len)
174 /* We cannot map in regular files in VxWorks. */
175 COMPQUIET(env, NULL);
176 COMPQUIET(addr, NULL);
178 return (DB_OPNOTSUP);
182 * __os_segdata_init --
183 * Initializes the library's table of shared memory segments.
184 * Called once on the first time through __os_segdata_new().
187 __os_segdata_init(env)
192 if (__os_segdata != NULL) {
193 __db_errx(env, "shared memory segment already exists");
198 * The lock init call returns a locked lock.
200 DB_BEGIN_SINGLE_THREAD;
201 __os_segdata_size = OS_SEGDATA_STARTING_SIZE;
202 ret = __os_calloc(env,
203 __os_segdata_size, sizeof(os_segdata_t), &__os_segdata);
204 DB_END_SINGLE_THREAD;
209 * __os_segdata_destroy --
210 * Destroys the library's table of shared memory segments. It also
211 * frees all linked data: the segments themselves, and their names.
212 * Currently not called. This function should be called if the
213 * user creates a function to unload or shutdown.
216 __os_segdata_destroy(env)
222 if (__os_segdata == NULL)
225 DB_BEGIN_SINGLE_THREAD;
226 for (i = 0; i < __os_segdata_size; i++) {
227 p = &__os_segdata[i];
228 if (p->name != NULL) {
229 __os_free(env, p->name);
232 if (p->segment != NULL) {
233 __os_free(env, p->segment);
239 __os_free(env, __os_segdata);
241 __os_segdata_size = 0;
242 DB_END_SINGLE_THREAD;
248 * __os_segdata_allocate --
249 * Creates a new segment of the specified size, optionally with the
252 * Assumes it is called with the SEGDATA lock taken.
255 __os_segdata_allocate(env, name, infop, rp)
267 if ((ret = __os_segdata_new(env, &id)) != 0)
270 p = &__os_segdata[id];
271 if ((ret = __os_calloc(env, 1, rp->size, &p->segment)) != 0)
273 if ((ret = __os_strdup(env, name, &p->name)) != 0) {
274 __os_free(env, p->segment);
279 p->segid = dbenv->shm_key + infop->id - 1;
281 infop->addr = p->segment;
288 * __os_segdata_new --
289 * Finds a new segdata slot. Does not initialise it, so the fd returned
290 * is only valid until you call this again.
292 * Assumes it is called with the SEGDATA lock taken.
295 __os_segdata_new(env, segidp)
302 if (__os_segdata == NULL) {
303 __db_errx(env, "shared memory segment not initialized");
307 for (i = 0; i < __os_segdata_size; i++) {
308 p = &__os_segdata[i];
309 if (p->segment == NULL) {
316 * No more free slots, expand.
318 newsize = __os_segdata_size + OS_SEGDATA_INCREMENT;
319 if ((ret = __os_realloc(env, newsize * sizeof(os_segdata_t),
320 &__os_segdata)) != 0)
322 memset(&__os_segdata[__os_segdata_size],
323 0, OS_SEGDATA_INCREMENT * sizeof(os_segdata_t));
325 *segidp = __os_segdata_size;
326 __os_segdata_size = newsize;
332 * __os_segdata_find_byname --
333 * Finds a segment by its name and shm_key.
335 * Assumes it is called with the SEGDATA lock taken.
338 __os_segdata_find_byname(env, name, infop, rp)
351 if (__os_segdata == NULL) {
352 __db_errx(env, "shared memory segment not initialized");
357 __db_errx(env, "no segment name given");
362 * If we are creating the region, compute the segid.
363 * If we are joining the region, we use the segid in the
364 * index we are given.
366 if (F_ISSET(infop, REGION_CREATE))
367 segid = dbenv->shm_key + (infop->id - 1);
369 if (rp->segid >= __os_segdata_size ||
370 rp->segid == INVALID_REGION_SEGID) {
371 __db_errx(env, "Invalid segment id given");
374 segid = __os_segdata[rp->segid].segid;
376 for (i = 0; i < __os_segdata_size; i++) {
377 p = &__os_segdata[i];
378 if (p->name != NULL && strcmp(name, p->name) == 0 &&
380 infop->addr = p->segment;
389 * __os_segdata_release --
390 * Free a segdata entry.
393 __os_segdata_release(env, rp, is_locked)
400 if (__os_segdata == NULL) {
401 __db_errx(env, "shared memory segment not initialized");
405 if (rp->segid < 0 || rp->segid >= __os_segdata_size) {
406 __db_errx(env, "segment id %ld out of range", rp->segid);
411 DB_BEGIN_SINGLE_THREAD;
412 p = &__os_segdata[rp->segid];
413 if (p->name != NULL) {
414 __os_free(env, p->name);
417 if (p->segment != NULL) {
418 __os_free(env, p->segment);
423 DB_END_SINGLE_THREAD;
425 /* Any shrink-table logic could go here */