Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

os_vx_map.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1998-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * This code is derived from software contributed to Sleepycat Software by
00008  * Frederick G.M. Roeber of Netscape Communications Corp.
00009  *
00010  * $Id: os_vx_map.c,v 12.1 2005/06/16 20:23:26 bostic Exp $
00011  */
00012 
00013 #include "db_config.h"
00014 
00015 #ifndef NO_SYSTEM_INCLUDES
00016 #include <sys/types.h>
00017 #include <string.h>
00018 #endif
00019 
00020 #include "db_int.h"
00021 
00022 /*
00023  * DB uses memory-mapped files for two things:
00024  *      faster access of read-only databases, and
00025  *      shared memory for process synchronization and locking.
00026  * The code carefully does not mix the two uses.  The first-case uses are
00027  * actually written such that memory-mapping isn't really required -- it's
00028  * merely a convenience -- so we don't have to worry much about it.  In the
00029  * second case, it's solely used as a shared memory mechanism, so that's
00030  * all we have to replace.
00031  *
00032  * All memory in VxWorks is shared, and a task can allocate memory and keep
00033  * notes.  So I merely have to allocate memory, remember the "filename" for
00034  * that memory, and issue small-integer segment IDs which index the list of
00035  * these shared-memory segments. Subsequent opens are checked against the
00036  * list of already open segments.
00037  */
00038 typedef struct {
00039         void *segment;                  /* Segment address. */
00040         u_int32_t size;                 /* Segment size. */
00041         char *name;                     /* Segment name. */
00042         long segid;                     /* Segment ID. */
00043 } os_segdata_t;
00044 
00045 static os_segdata_t *__os_segdata;      /* Segment table. */
00046 static int __os_segdata_size;           /* Segment table size. */
00047 
00048 #define OS_SEGDATA_STARTING_SIZE 16
00049 #define OS_SEGDATA_INCREMENT     16
00050 
00051 static int __os_segdata_allocate
00052                __P((DB_ENV *, const char *, REGINFO *, REGION *));
00053 static int __os_segdata_find_byname
00054                __P((DB_ENV *, const char *, REGINFO *, REGION *));
00055 static int __os_segdata_init __P((DB_ENV *));
00056 static int __os_segdata_new __P((DB_ENV *, int *));
00057 static int __os_segdata_release __P((DB_ENV *, REGION *, int));
00058 
00059 /*
00060  * __os_r_sysattach --
00061  *      Create/join a shared memory region.
00062  *
00063  * PUBLIC: int __os_r_sysattach __P((DB_ENV *, REGINFO *, REGION *));
00064  */
00065 int
00066 __os_r_sysattach(dbenv, infop, rp)
00067         DB_ENV *dbenv;
00068         REGINFO *infop;
00069         REGION *rp;
00070 {
00071         int ret;
00072 
00073         if (__os_segdata == NULL)
00074                 __os_segdata_init(dbenv);
00075 
00076         DB_BEGIN_SINGLE_THREAD;
00077 
00078         /* Try to find an already existing segment. */
00079         ret = __os_segdata_find_byname(dbenv, infop->name, infop, rp);
00080 
00081         /*
00082          * If we are trying to join a region, it is easy, either we
00083          * found it and we return, or we didn't find it and we return
00084          * an error that it doesn't exist.
00085          */
00086         if (!F_ISSET(infop, REGION_CREATE)) {
00087                 if (ret != 0) {
00088                         __db_err(dbenv, "segment %s does not exist",
00089                             infop->name);
00090                         ret = EAGAIN;
00091                 }
00092                 goto out;
00093         }
00094 
00095         /*
00096          * If we get here, we are trying to create the region.
00097          * There are several things to consider:
00098          * - if we have an error (not a found or not-found value), return.
00099          * - they better have shm_key set.
00100          * - if the region is already there (ret == 0 from above),
00101          * assume the application crashed and we're restarting.
00102          * Delete the old region.
00103          * - try to create the region.
00104          */
00105         if (ret != 0 && ret != ENOENT)
00106                 goto out;
00107 
00108         if (dbenv->shm_key == INVALID_REGION_SEGID) {
00109                 __db_err(dbenv, "no base shared memory ID specified");
00110                 ret = EAGAIN;
00111                 goto out;
00112         }
00113         if (ret == 0 && __os_segdata_release(dbenv, rp, 1) != 0) {
00114                 __db_err(dbenv,
00115                     "key: %ld: shared memory region already exists",
00116                     dbenv->shm_key + (infop->id - 1));
00117                 ret = EAGAIN;
00118                 goto out;
00119         }
00120 
00121         ret = __os_segdata_allocate(dbenv, infop->name, infop, rp);
00122 out:
00123         DB_END_SINGLE_THREAD;
00124         return (ret);
00125 }
00126 
00127 /*
00128  * __os_r_sysdetach --
00129  *      Detach from a shared region.
00130  *
00131  * PUBLIC: int __os_r_sysdetach __P((DB_ENV *, REGINFO *, int));
00132  */
00133 int
00134 __os_r_sysdetach(dbenv, infop, destroy)
00135         DB_ENV *dbenv;
00136         REGINFO *infop;
00137         int destroy;
00138 {
00139         /*
00140          * If just detaching, there is no mapping to discard.
00141          * If destroying, remove the region.
00142          */
00143         if (destroy)
00144                 return (__os_segdata_release(dbenv, infop->rp, 0));
00145         return (0);
00146 }
00147 
00148 /*
00149  * __os_mapfile --
00150  *      Map in a shared memory file.
00151  *
00152  * PUBLIC: int __os_mapfile __P((DB_ENV *,
00153  * PUBLIC:    char *, DB_FH *, size_t, int, void **));
00154  */
00155 int
00156 __os_mapfile(dbenv, path, fhp, len, is_rdonly, addrp)
00157         DB_ENV *dbenv;
00158         char *path;
00159         DB_FH *fhp;
00160         int is_rdonly;
00161         size_t len;
00162         void **addrp;
00163 {
00164         /* We cannot map in regular files in VxWorks. */
00165         COMPQUIET(dbenv, NULL);
00166         COMPQUIET(path, NULL);
00167         COMPQUIET(fhp, NULL);
00168         COMPQUIET(is_rdonly, 0);
00169         COMPQUIET(len, 0);
00170         COMPQUIET(addrp, NULL);
00171         return (EINVAL);
00172 }
00173 
00174 /*
00175  * __os_unmapfile --
00176  *      Unmap the shared memory file.
00177  *
00178  * PUBLIC: int __os_unmapfile __P((DB_ENV *, void *, size_t));
00179  */
00180 int
00181 __os_unmapfile(dbenv, addr, len)
00182         DB_ENV *dbenv;
00183         void *addr;
00184         size_t len;
00185 {
00186         /* We cannot map in regular files in VxWorks. */
00187         COMPQUIET(dbenv, NULL);
00188         COMPQUIET(addr, NULL);
00189         COMPQUIET(len, 0);
00190         return (EINVAL);
00191 }
00192 
00193 /*
00194  * __os_segdata_init --
00195  *      Initializes the library's table of shared memory segments.
00196  *      Called once on the first time through __os_segdata_new().
00197  */
00198 static int
00199 __os_segdata_init(dbenv)
00200         DB_ENV *dbenv;
00201 {
00202         int ret;
00203 
00204         if (__os_segdata != NULL) {
00205                 __db_err(dbenv, "shared memory segment already exists");
00206                 return (EEXIST);
00207         }
00208 
00209         /*
00210          * The lock init call returns a locked lock.
00211          */
00212         DB_BEGIN_SINGLE_THREAD;
00213         __os_segdata_size = OS_SEGDATA_STARTING_SIZE;
00214         ret = __os_calloc(dbenv,
00215             __os_segdata_size, sizeof(os_segdata_t), &__os_segdata);
00216         DB_END_SINGLE_THREAD;
00217         return (ret);
00218 }
00219 
00220 /*
00221  * __os_segdata_destroy --
00222  *      Destroys the library's table of shared memory segments.  It also
00223  *      frees all linked data: the segments themselves, and their names.
00224  *      Currently not called.  This function should be called if the
00225  *      user creates a function to unload or shutdown.
00226  *
00227  * PUBLIC: int __os_segdata_destroy __P((DB_ENV *));
00228  */
00229 int
00230 __os_segdata_destroy(dbenv)
00231         DB_ENV *dbenv;
00232 {
00233         os_segdata_t *p;
00234         int i;
00235 
00236         if (__os_segdata == NULL)
00237                 return (0);
00238 
00239         DB_BEGIN_SINGLE_THREAD;
00240         for (i = 0; i < __os_segdata_size; i++) {
00241                 p = &__os_segdata[i];
00242                 if (p->name != NULL) {
00243                         __os_free(dbenv, p->name);
00244                         p->name = NULL;
00245                 }
00246                 if (p->segment != NULL) {
00247                         __os_free(dbenv, p->segment);
00248                         p->segment = NULL;
00249                 }
00250                 p->size = 0;
00251         }
00252 
00253         __os_free(dbenv, __os_segdata);
00254         __os_segdata = NULL;
00255         __os_segdata_size = 0;
00256         DB_END_SINGLE_THREAD;
00257 
00258         return (0);
00259 }
00260 
00261 /*
00262  * __os_segdata_allocate --
00263  *      Creates a new segment of the specified size, optionally with the
00264  *      specified name.
00265  *
00266  * Assumes it is called with the SEGDATA lock taken.
00267  */
00268 static int
00269 __os_segdata_allocate(dbenv, name, infop, rp)
00270         DB_ENV *dbenv;
00271         const char *name;
00272         REGINFO *infop;
00273         REGION *rp;
00274 {
00275         os_segdata_t *p;
00276         int id, ret;
00277 
00278         if ((ret = __os_segdata_new(dbenv, &id)) != 0)
00279                 return (ret);
00280 
00281         p = &__os_segdata[id];
00282         if ((ret = __os_calloc(dbenv, 1, rp->size, &p->segment)) != 0)
00283                 return (ret);
00284         if ((ret = __os_strdup(dbenv, name, &p->name)) != 0) {
00285                 __os_free(dbenv, p->segment);
00286                 p->segment = NULL;
00287                 return (ret);
00288         }
00289         p->size = rp->size;
00290         p->segid = dbenv->shm_key + infop->id - 1;
00291 
00292         infop->addr = p->segment;
00293         rp->segid = id;
00294 
00295         return (0);
00296 }
00297 
00298 /*
00299  * __os_segdata_new --
00300  *      Finds a new segdata slot.  Does not initialise it, so the fd returned
00301  *      is only valid until you call this again.
00302  *
00303  * Assumes it is called with the SEGDATA lock taken.
00304  */
00305 static int
00306 __os_segdata_new(dbenv, segidp)
00307         DB_ENV *dbenv;
00308         int *segidp;
00309 {
00310         os_segdata_t *p;
00311         int i, newsize, ret;
00312 
00313         if (__os_segdata == NULL) {
00314                 __db_err(dbenv, "shared memory segment not initialized");
00315                 return (EAGAIN);
00316         }
00317 
00318         for (i = 0; i < __os_segdata_size; i++) {
00319                 p = &__os_segdata[i];
00320                 if (p->segment == NULL) {
00321                         *segidp = i;
00322                         return (0);
00323                 }
00324         }
00325 
00326         /*
00327          * No more free slots, expand.
00328          */
00329         newsize = __os_segdata_size + OS_SEGDATA_INCREMENT;
00330         if ((ret = __os_realloc(dbenv, newsize * sizeof(os_segdata_t),
00331             &__os_segdata)) != 0)
00332                 return (ret);
00333         memset(&__os_segdata[__os_segdata_size],
00334             0, OS_SEGDATA_INCREMENT * sizeof(os_segdata_t));
00335 
00336         *segidp = __os_segdata_size;
00337         __os_segdata_size = newsize;
00338 
00339         return (0);
00340 }
00341 
00342 /*
00343  * __os_segdata_find_byname --
00344  *      Finds a segment by its name and shm_key.
00345  *
00346  * Assumes it is called with the SEGDATA lock taken.
00347  *
00348  * PUBLIC: __os_segdata_find_byname
00349  * PUBLIC:     __P((DB_ENV *, const char *, REGINFO *, REGION *));
00350  */
00351 static int
00352 __os_segdata_find_byname(dbenv, name, infop, rp)
00353         DB_ENV *dbenv;
00354         const char *name;
00355         REGINFO *infop;
00356         REGION *rp;
00357 {
00358         os_segdata_t *p;
00359         long segid;
00360         int i;
00361 
00362         if (__os_segdata == NULL) {
00363                 __db_err(dbenv, "shared memory segment not initialized");
00364                 return (EAGAIN);
00365         }
00366 
00367         if (name == NULL) {
00368                 __db_err(dbenv, "no segment name given");
00369                 return (EAGAIN);
00370         }
00371 
00372         /*
00373          * If we are creating the region, compute the segid.
00374          * If we are joining the region, we use the segid in the
00375          * index we are given.
00376          */
00377         if (F_ISSET(infop, REGION_CREATE))
00378                 segid = dbenv->shm_key + (infop->id - 1);
00379         else {
00380                 if (rp->segid >= __os_segdata_size ||
00381                     rp->segid == INVALID_REGION_SEGID) {
00382                         __db_err(dbenv, "Invalid segment id given");
00383                         return (EAGAIN);
00384                 }
00385                 segid = __os_segdata[rp->segid].segid;
00386         }
00387         for (i = 0; i < __os_segdata_size; i++) {
00388                 p = &__os_segdata[i];
00389                 if (p->name != NULL && strcmp(name, p->name) == 0 &&
00390                     p->segid == segid) {
00391                         infop->addr = p->segment;
00392                         rp->segid = i;
00393                         return (0);
00394                 }
00395         }
00396         return (ENOENT);
00397 }
00398 
00399 /*
00400  * __os_segdata_release --
00401  *      Free a segdata entry.
00402  */
00403 static int
00404 __os_segdata_release(dbenv, rp, is_locked)
00405         DB_ENV *dbenv;
00406         REGION *rp;
00407         int is_locked;
00408 {
00409         os_segdata_t *p;
00410 
00411         if (__os_segdata == NULL) {
00412                 __db_err(dbenv, "shared memory segment not initialized");
00413                 return (EAGAIN);
00414         }
00415 
00416         if (rp->segid < 0 || rp->segid >= __os_segdata_size) {
00417                 __db_err(dbenv, "segment id %ld out of range", rp->segid);
00418                 return (EINVAL);
00419         }
00420 
00421         if (is_locked == 0)
00422                 DB_BEGIN_SINGLE_THREAD;
00423         p = &__os_segdata[rp->segid];
00424         if (p->name != NULL) {
00425                 __os_free(dbenv, p->name);
00426                 p->name = NULL;
00427         }
00428         if (p->segment != NULL) {
00429                 __os_free(dbenv, p->segment);
00430                 p->segment = NULL;
00431         }
00432         p->size = 0;
00433         if (is_locked == 0)
00434                 DB_END_SINGLE_THREAD;
00435 
00436         /* Any shrink-table logic could go here */
00437 
00438         return (0);
00439 }

Generated on Sun Dec 25 12:14:42 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2