diff options
author | jbj <devnull@localhost> | 2001-03-21 18:33:35 +0000 |
---|---|---|
committer | jbj <devnull@localhost> | 2001-03-21 18:33:35 +0000 |
commit | 731946f4b90eb1173452dd30f1296dd825155d82 (patch) | |
tree | 67535f54ecb7e5463c06e62044e4efd84ae0291d /db/os_vxworks/os_map.c | |
parent | 7ed904da030dc4640ff9bce8458ba07cc09d830d (diff) | |
download | librpm-tizen-731946f4b90eb1173452dd30f1296dd825155d82.tar.gz librpm-tizen-731946f4b90eb1173452dd30f1296dd825155d82.tar.bz2 librpm-tizen-731946f4b90eb1173452dd30f1296dd825155d82.zip |
Initial revision
CVS patchset: 4644
CVS date: 2001/03/21 18:33:35
Diffstat (limited to 'db/os_vxworks/os_map.c')
-rw-r--r-- | db/os_vxworks/os_map.c | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/db/os_vxworks/os_map.c b/db/os_vxworks/os_map.c new file mode 100644 index 000000000..7397995d1 --- /dev/null +++ b/db/os_vxworks/os_map.c @@ -0,0 +1,440 @@ +/*- + * 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); +} |