gecko-dev/db/os.win16/os_map.c

413 строки
8.8 KiB
C

/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1998
* 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 "config.h"
#ifndef lint
static const char sccsid[] = "@(#)os_map.c 10.6 (Sleepycat) 4/25/98";
#endif /* not lint */
#include "db_int.h"
#include "common_ext.h"
/*
* DB version 2 uses memory-mapped files for two things: 1) faster access of
* read-only databases, and 2) 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.
*
* The mechanism I use for shared memory on Win16 is actually fairly simple.
* All memory in Win16 is shared, and a DLL can allocate memory and keep notes.
* This implementation of Win16, at least, is entirely done as a DLL. So I
* merely have to allocate memory, remember the "filename" for that memory,
* and issue small-integer segment IDs which index the DLL's 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. */
} 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_map __P((char *, REGINFO *));
static int __os_segdata_allocate __P((const char *, REGINFO *));
static int __os_segdata_find_byname __P((const char *, REGINFO *));
static int __os_segdata_new __P((int *));
static int __os_segdata_release __P((int));
/*
* __db_mapanon_ok --
* Return if this OS can support anonymous memory regions.
*
* PUBLIC: int __db_mapanon_ok __P((int));
*/
int
__db_mapanon_ok(need_names)
int need_names;
{
COMPQUIET(need_names, 0);
/*
* All Win16 regions are in named anonymous shared memory,
* so the answer is always yes.
*/
return (0);
}
/*
* __db_mapinit --
* Return if shared regions need to be initialized.
*
* PUBLIC: int __db_mapinit __P((void));
*/
int
__db_mapinit()
{
/* Win16 regions do not need to be fully written. */
return (0);
}
/*
* __db_mapregion --
* Attach to a shared memory region.
*
* PUBLIC: int __db_mapregion __P((char *, REGINFO *));
*/
int
__db_mapregion(path, infop)
char *path;
REGINFO *infop;
{
/* If the user replaces the map call, call through their interface. */
if (__db_jump.j_map != NULL)
return (__db_jump.j_map(path, infop->fd, infop->size,
1, F_ISSET(infop, REGION_ANONYMOUS), 0, &infop->addr));
/*
* XXX
* We could actually grow regions without a lot of difficulty, but
* since the maximum region is 64K, it's unclear to me it's worth
* the effort.
*/
return (__os_map(path, infop));
}
/*
* __db_unmapregion --
* Detach from the shared memory region.
*
* PUBLIC: int __db_unmapregion __P((REGINFO *));
*/
int
__db_unmapregion(infop)
REGINFO *infop;
{
if (__db_jump.j_unmap != NULL)
return (__db_jump.j_unmap(infop->addr, infop->size));
/* There's no mapping to discard, we're done. */
return (0);
}
/*
* __db_unlinkregion --
* Remove the shared memory region.
*
* PUBLIC: int __db_unlinkregion __P((char *, REGINFO *));
*/
int
__db_unlinkregion(name, infop)
char *name;
REGINFO *infop;
{
COMPQUIET(infop, NULL);
if (__db_jump.j_runlink != NULL)
return (__db_jump.j_runlink(name));
return (__os_segdata_release(infop->segid));
}
/*
* __db_mapfile --
* Map in a shared memory file.
*
* PUBLIC: int __db_mapfile __P((char *, int, size_t, int, void **));
*/
int
__db_mapfile(path, fd, len, is_rdonly, addr)
char *path;
int fd, is_rdonly;
size_t len;
void **addr;
{
if (__db_jump.j_map != NULL)
return (__db_jump.j_map(path, fd, len, 0, 0, is_rdonly, addr));
/* We cannot map in regular files in Win16. */
return (EINVAL);
}
/*
* __db_unmapfile --
* Unmap the shared memory file.
*
* PUBLIC: int __db_unmapfile __P((void *, size_t));
*/
int
__db_unmapfile(addr, len)
void *addr;
size_t len;
{
if (__db_jump.j_unmap != NULL)
return (__db_jump.j_unmap(addr, len));
/* We cannot map in regular files in Win16. */
return (EINVAL);
}
/*
* __os_map --
* Create/find a shared region.
*/
static int
__os_map(path, infop)
char *path;
REGINFO *infop;
{
int ret;
/* Try to find an already existing segment. */
if (__os_segdata_find_byname(path, infop) == 0)
return (0);
/*
* If we're trying to join the region and failing, assume
* that there was a reboot and the region no longer exists.
*/
if (!F_ISSET(infop, REGION_CREATED))
return (EAGAIN);
/* Create a new segment. */
if ((ret = __os_segdata_allocate(path, infop)) != 0)
return (ret);
return (0);
}
/*
* __os_segdata_init --
* Initialises the library's table of shared memory segments. Called
* (once!) from the DLL main routine.
*
* PUBLIC: int __os_segdata_init __P((void));
*/
int
__os_segdata_init()
{
if (__os_segdata != NULL)
return (EEXIST);
__os_segdata_size = OS_SEGDATA_STARTING_SIZE;
if ((__os_segdata = (os_segdata_t *)
__db_calloc(__os_segdata_size, sizeof(os_segdata_t))) == NULL)
return (ENOMEM);
return (0);
}
/*
* __os_segdata_destroy --
* Destroys the library's table of shared memory segments. It also
* frees all linked data: the segments themselves, and their names.
* Called (once!) from the DLL shutdown routine.
*
* PUBLIC: int __os_segdata_destroy __P((void));
*/
int
__os_segdata_destroy()
{
os_segdata_t *p;
int i;
if (__os_segdata == NULL)
return (0);
for (i = 0; i < __os_segdata_size; i++) {
p = &__os_segdata[i];
if (p->name != NULL) {
FREES(p->name);
p->name = NULL;
}
if (p->segment != NULL) {
FREE(p->segment, p->size);
p->segment = NULL;
}
p->size = 0;
}
FREE(__os_segdata, __os_segdata_size * sizeof(os_segdata_t));
__os_segdata = NULL;
__os_segdata_size = 0;
return (0);
}
/*
* __os_segdata_allocate --
* Creates a new segment of the specified size, optionally with the
* specified name.
*/
static int
__os_segdata_allocate(name, infop)
const char *name;
REGINFO *infop;
{
os_segdata_t *p;
int segid, ret;
if ((ret = __os_segdata_new(&segid)) != 0)
return (ret);
p = &__os_segdata[segid];
if ((p->segment = (void *)__db_calloc(infop->size, 1)) == NULL)
return (ENOMEM);
if ((p->name = __db_strdup(name)) == NULL) {
FREE(p->segment, infop->size);
p->segment = NULL;
return (ENOMEM);
}
p->size = infop->size;
infop->addr = p->segment;
infop->segid = segid;
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.
*/
static int
__os_segdata_new(segidp)
int *segidp;
{
os_segdata_t *p, *newptr;
int i, newsize;
if (__os_segdata == NULL)
return (EAGAIN);
for (i = 0; i < __os_segdata_size; i++) {
p = &__os_segdata[i];
if (p->segment == NULL) {
*segidp = i;
return (0);
}
}
/*
* This test is actually pedantic, since I can't malloc more than 64K,
* and the structure is more than two bytes big. But I'm a pedant.
*/
if ((u_int)__os_segdata_size >=
(32768 / sizeof(os_segdata_t) - OS_SEGDATA_INCREMENT))
return (ENOMEM);
newsize = __os_segdata_size + OS_SEGDATA_INCREMENT;
if ((newptr = (os_segdata_t *)
__db_realloc(__os_segdata, newsize * sizeof(os_segdata_t))) == NULL)
return (ENOMEM);
memset(&newptr[__os_segdata_size],
0, OS_SEGDATA_INCREMENT * sizeof(os_segdata_t));
__os_segdata = newptr;
__os_segdata_size = newsize;
*segidp = __os_segdata_size;
return (0);
}
/*
* __os_segdata_find_byname --
* Finds a segment by its name.
*
* PUBLIC: __os_segdata_find_byname __P((const char *, REGINFO *));
*/
static int
__os_segdata_find_byname(name, infop)
const char *name;
REGINFO *infop;
{
os_segdata_t *p;
int i;
if (__os_segdata == NULL)
return (EAGAIN);
if (name == NULL)
return (ENOENT);
for (i = 0; i < __os_segdata_size; i++) {
p = &__os_segdata[i];
if (p->name != NULL && strcmp(name, p->name) == 0) {
infop->addr = p->segment;
infop->segid = i;
return (0);
}
}
return (ENOENT);
}
/*
* __os_segdata_release --
* Free a segdata entry.
*/
static int
__os_segdata_release(segid)
int segid;
{
os_segdata_t *p;
if (__os_segdata == NULL)
return (EAGAIN);
if (segid < 0 || segid >= __os_segdata_size)
return (EINVAL);
p = &__os_segdata[segid];
if (p->name != NULL) {
FREES(p->name);
p->name = NULL;
}
if (p->segment != NULL) {
FREE(p->segment, p->size);
p->segment = NULL;
}
p->size = 0;
/* Any shrink-table logic could go here */
return (0);
}