os_map.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:10k
- /*-
- * See the file LICENSE for redistribution information.
- *
- * Copyright (c) 1998, 1999, 2000
- * Sleepycat Software. All rights reserved.
- *
- * This code is derived from software contributed to Sleepycat Software by
- * Frederick G.M. Roeber of Netscape Communications Corp.
- */
- #include "db_config.h"
- #ifndef lint
- static const char revid[] = "$Id: os_map.c,v 1.14 2000/12/04 19:01:43 sue Exp $";
- #endif /* not lint */
- #ifndef NO_SYSTEM_INCLUDES
- #include <sys/types.h>
- #include <string.h>
- #endif
- #include "db_int.h"
- #include "common_ext.h"
- /*
- * DB uses memory-mapped files for two things:
- * faster access of read-only databases, and
- * shared memory for process synchronization and locking.
- * The code carefully does not mix the two uses. The first-case uses are
- * actually written such that memory-mapping isn't really required -- it's
- * merely a convenience -- so we don't have to worry much about it. In the
- * second case, it's solely used as a shared memory mechanism, so that's
- * all we have to replace.
- *
- * All memory in VxWorks is shared, and a task can allocate memory and keep
- * notes. So I merely have to allocate memory, remember the "filename" for
- * that memory, and issue small-integer segment IDs which index the list of
- * these shared-memory segments. Subsequent opens are checked against the
- * list of already open segments.
- */
- typedef struct {
- void *segment; /* Segment address. */
- u_int32_t size; /* Segment size. */
- char *name; /* Segment name. */
- long segid; /* Segment ID. */
- } os_segdata_t;
- static os_segdata_t *__os_segdata; /* Segment table. */
- static int __os_segdata_size; /* Segment table size. */
- #define OS_SEGDATA_STARTING_SIZE 16
- #define OS_SEGDATA_INCREMENT 16
- static int __os_segdata_allocate
- __P((DB_ENV *, const char *, REGINFO *, REGION *));
- static int __os_segdata_find_byname
- __P((DB_ENV *, const char *, REGINFO *, REGION *));
- static int __os_segdata_init __P((DB_ENV *));
- static int __os_segdata_new __P((DB_ENV *, int *));
- static int __os_segdata_release __P((DB_ENV *, REGION *, int));
- /*
- * __os_r_sysattach --
- * Create/join a shared memory region.
- *
- * PUBLIC: int __os_r_sysattach __P((DB_ENV *, REGINFO *, REGION *));
- */
- int
- __os_r_sysattach(dbenv, infop, rp)
- DB_ENV *dbenv;
- REGINFO *infop;
- REGION *rp;
- {
- int ret;
- if (__os_segdata == NULL)
- __os_segdata_init(dbenv);
- DB_BEGIN_SINGLE_THREAD;
- /* Try to find an already existing segment. */
- ret = __os_segdata_find_byname(dbenv, infop->name, infop, rp);
- /*
- * If we are trying to join a region, it is easy, either we
- * found it and we return, or we didn't find it and we return
- * an error that it doesn't exist.
- */
- if (!F_ISSET(infop, REGION_CREATE)) {
- if (ret != 0) {
- __db_err(dbenv, "segment %s does not exist",
- infop->name);
- ret = EAGAIN;
- }
- goto out;
- }
- /*
- * If we get here, we are trying to create the region.
- * There are several things to consider:
- * - if we have an error (not a found or not-found value), return.
- * - they better have shm_key set.
- * - if the region is already there (ret == 0 from above),
- * assume the application crashed and we're restarting.
- * Delete the old region.
- * - try to create the region.
- */
- if (ret != 0 && ret != ENOENT)
- goto out;
- if (dbenv->shm_key == INVALID_REGION_SEGID) {
- __db_err(dbenv, "no base shared memory ID specified");
- ret = EAGAIN;
- goto out;
- }
- if (ret == 0 && __os_segdata_release(dbenv, rp, 1) != 0) {
- __db_err(dbenv,
- "key: %ld: shared memory region already exists",
- dbenv->shm_key + (infop->id - 1));
- ret = EAGAIN;
- goto out;
- }
- ret = __os_segdata_allocate(dbenv, infop->name, infop, rp);
- out:
- DB_END_SINGLE_THREAD;
- return (ret);
- }
- /*
- * __os_r_sysdetach --
- * Detach from a shared region.
- *
- * PUBLIC: int __os_r_sysdetach __P((DB_ENV *, REGINFO *, int));
- */
- int
- __os_r_sysdetach(dbenv, infop, destroy)
- DB_ENV *dbenv;
- REGINFO *infop;
- int destroy;
- {
- /*
- * If just detaching, there is no mapping to discard.
- * If destroying, remove the region.
- */
- if (destroy)
- return (__os_segdata_release(dbenv, infop->rp, 0));
- return (0);
- }
- /*
- * __os_mapfile --
- * Map in a shared memory file.
- *
- * PUBLIC: int __os_mapfile __P((DB_ENV *,
- * PUBLIC: char *, DB_FH *, size_t, int, void **));
- */
- int
- __os_mapfile(dbenv, path, fhp, len, is_rdonly, addrp)
- DB_ENV *dbenv;
- char *path;
- DB_FH *fhp;
- int is_rdonly;
- size_t len;
- void **addrp;
- {
- /* We cannot map in regular files in VxWorks. */
- COMPQUIET(dbenv, NULL);
- COMPQUIET(path, NULL);
- COMPQUIET(fhp, NULL);
- COMPQUIET(is_rdonly, 0);
- COMPQUIET(len, 0);
- COMPQUIET(addrp, NULL);
- return (EINVAL);
- }
- /*
- * __os_unmapfile --
- * Unmap the shared memory file.
- *
- * PUBLIC: int __os_unmapfile __P((DB_ENV *, void *, size_t));
- */
- int
- __os_unmapfile(dbenv, addr, len)
- DB_ENV *dbenv;
- void *addr;
- size_t len;
- {
- /* We cannot map in regular files in VxWorks. */
- COMPQUIET(addr, NULL);
- COMPQUIET(len, 0);
- return (EINVAL);
- }
- /*
- * __os_segdata_init --
- * Initializes the library's table of shared memory segments.
- * Called once on the first time through __os_segdata_new().
- */
- static int
- __os_segdata_init(dbenv)
- DB_ENV *dbenv;
- {
- int ret;
- if (__os_segdata != NULL) {
- __db_err(dbenv, "shared memory segment already exists");
- return (EEXIST);
- }
- /*
- * The lock init call returns a locked lock.
- */
- DB_BEGIN_SINGLE_THREAD;
- __os_segdata_size = OS_SEGDATA_STARTING_SIZE;
- ret = __os_calloc(dbenv,
- __os_segdata_size, sizeof(os_segdata_t), &__os_segdata);
- DB_END_SINGLE_THREAD;
- return (ret);
- }
- /*
- * __os_segdata_destroy --
- * Destroys the library's table of shared memory segments. It also
- * frees all linked data: the segments themselves, and their names.
- * Currently not called. This function should be called if the
- * user creates a function to unload or shutdown.
- *
- * PUBLIC: int __os_segdata_destroy __P((void));
- */
- int
- __os_segdata_destroy()
- {
- os_segdata_t *p;
- int i;
- if (__os_segdata == NULL)
- return (0);
- DB_BEGIN_SINGLE_THREAD;
- for (i = 0; i < __os_segdata_size; i++) {
- p = &__os_segdata[i];
- if (p->name != NULL) {
- __os_freestr(p->name);
- p->name = NULL;
- }
- if (p->segment != NULL) {
- __os_free(p->segment, p->size);
- p->segment = NULL;
- }
- p->size = 0;
- }
- __os_free(__os_segdata, __os_segdata_size * sizeof(os_segdata_t));
- __os_segdata = NULL;
- __os_segdata_size = 0;
- DB_END_SINGLE_THREAD;
- return (0);
- }
- /*
- * __os_segdata_allocate --
- * Creates a new segment of the specified size, optionally with the
- * specified name.
- *
- * Assumes it is called with the SEGDATA lock taken.
- */
- static int
- __os_segdata_allocate(dbenv, name, infop, rp)
- DB_ENV *dbenv;
- const char *name;
- REGINFO *infop;
- REGION *rp;
- {
- os_segdata_t *p;
- int id, ret;
- if ((ret = __os_segdata_new(dbenv, &id)) != 0)
- return (ret);
- p = &__os_segdata[id];
- if ((ret = __os_calloc(dbenv, 1, rp->size, &p->segment)) != 0)
- return (ret);
- if ((ret = __os_strdup(dbenv, name, &p->name)) != 0) {
- __os_free(p->segment, rp->size);
- p->segment = NULL;
- return (ret);
- }
- p->size = rp->size;
- p->segid = dbenv->shm_key + infop->id - 1;
- infop->addr = p->segment;
- rp->segid = id;
- return (0);
- }
- /*
- * __os_segdata_new --
- * Finds a new segdata slot. Does not initialise it, so the fd returned
- * is only valid until you call this again.
- *
- * Assumes it is called with the SEGDATA lock taken.
- */
- static int
- __os_segdata_new(dbenv, segidp)
- DB_ENV *dbenv;
- int *segidp;
- {
- os_segdata_t *p;
- int i, newsize, ret;
- if (__os_segdata == NULL) {
- __db_err(dbenv, "shared memory segment not initialized");
- return (EAGAIN);
- }
- for (i = 0; i < __os_segdata_size; i++) {
- p = &__os_segdata[i];
- if (p->segment == NULL) {
- *segidp = i;
- return (0);
- }
- }
- /*
- * No more free slots, expand.
- */
- newsize = __os_segdata_size + OS_SEGDATA_INCREMENT;
- if ((ret = __os_realloc(dbenv, newsize * sizeof(os_segdata_t),
- NULL, &__os_segdata)) != 0)
- return (ret);
- memset(&__os_segdata[__os_segdata_size],
- 0, OS_SEGDATA_INCREMENT * sizeof(os_segdata_t));
- *segidp = __os_segdata_size;
- __os_segdata_size = newsize;
- return (0);
- }
- /*
- * __os_segdata_find_byname --
- * Finds a segment by its name and shm_key.
- *
- * Assumes it is called with the SEGDATA lock taken.
- *
- * PUBLIC: __os_segdata_find_byname
- * PUBLIC: __P((DB_ENV *, const char *, REGINFO *, REGION *));
- */
- static int
- __os_segdata_find_byname(dbenv, name, infop, rp)
- DB_ENV *dbenv;
- const char *name;
- REGINFO *infop;
- REGION *rp;
- {
- os_segdata_t *p;
- long segid;
- int i;
- if (__os_segdata == NULL) {
- __db_err(dbenv, "shared memory segment not initialized");
- return (EAGAIN);
- }
- if (name == NULL) {
- __db_err(dbenv, "no segment name given");
- return (EAGAIN);
- }
- /*
- * If we are creating the region, compute the segid.
- * If we are joining the region, we use the segid in the
- * index we are given.
- */
- if (F_ISSET(infop, REGION_CREATE))
- segid = dbenv->shm_key + (infop->id - 1);
- else {
- if (rp->segid >= __os_segdata_size ||
- rp->segid == INVALID_REGION_SEGID) {
- __db_err(dbenv, "Invalid segment id given");
- return (EAGAIN);
- }
- segid = __os_segdata[rp->segid].segid;
- }
- for (i = 0; i < __os_segdata_size; i++) {
- p = &__os_segdata[i];
- if (p->name != NULL && strcmp(name, p->name) == 0 &&
- p->segid == segid) {
- infop->addr = p->segment;
- rp->segid = i;
- return (0);
- }
- }
- return (ENOENT);
- }
- /*
- * __os_segdata_release --
- * Free a segdata entry.
- */
- static int
- __os_segdata_release(dbenv, rp, is_locked)
- DB_ENV *dbenv;
- REGION *rp;
- int is_locked;
- {
- os_segdata_t *p;
- if (__os_segdata == NULL) {
- __db_err(dbenv, "shared memory segment not initialized");
- return (EAGAIN);
- }
- if (rp->segid < 0 || rp->segid >= __os_segdata_size) {
- __db_err(dbenv, "segment id %ld out of range", rp->segid);
- return (EINVAL);
- }
- if (is_locked == 0)
- DB_BEGIN_SINGLE_THREAD;
- p = &__os_segdata[rp->segid];
- if (p->name != NULL) {
- __os_freestr(p->name);
- p->name = NULL;
- }
- if (p->segment != NULL) {
- __os_free(p->segment, p->size);
- p->segment = NULL;
- }
- p->size = 0;
- if (is_locked == 0)
- DB_END_SINGLE_THREAD;
- /* Any shrink-table logic could go here */
- return (0);
- }