Import BSDDB 4.7.25 (as of svn r89086)
This commit is contained in:
33
os/os_abort.c
Normal file
33
os/os_abort.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2005,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_abort.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_abort --
|
||||
*
|
||||
* PUBLIC: void __os_abort __P((ENV *));
|
||||
*/
|
||||
void
|
||||
__os_abort(env)
|
||||
ENV *env;
|
||||
{
|
||||
__os_stack(env); /* Try and get a stack trace. */
|
||||
|
||||
#ifdef HAVE_ABORT
|
||||
abort(); /* Try and drop core. */
|
||||
/* NOTREACHED */
|
||||
#endif
|
||||
#ifdef SIGABRT
|
||||
(void)raise(SIGABRT); /* Try and drop core. */
|
||||
#endif
|
||||
exit(1); /* Quit anyway. */
|
||||
/* NOTREACHED */
|
||||
}
|
||||
24
os/os_abs.c
Normal file
24
os/os_abs.c
Normal file
@@ -0,0 +1,24 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_abs.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_abspath --
|
||||
* Return if a path is an absolute path.
|
||||
*
|
||||
* PUBLIC: int __os_abspath __P((const char *));
|
||||
*/
|
||||
int
|
||||
__os_abspath(path)
|
||||
const char *path;
|
||||
{
|
||||
return (path[0] == '/');
|
||||
}
|
||||
176
os/os_addrinfo.c
Normal file
176
os/os_addrinfo.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2006,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_addrinfo.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#define __INCLUDE_NETWORKING 1
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_getaddrinfo and __os_freeaddrinfo wrap the getaddrinfo and freeaddrinfo
|
||||
* calls, as well as the associated platform dependent error handling, mapping
|
||||
* the error return to a ANSI C/POSIX error return.
|
||||
*/
|
||||
|
||||
/*
|
||||
* __os_getaddrinfo --
|
||||
*
|
||||
* PUBLIC: #if defined(HAVE_REPLICATION_THREADS)
|
||||
* PUBLIC: int __os_getaddrinfo __P((ENV *, const char *, u_int,
|
||||
* PUBLIC: const char *, const ADDRINFO *, ADDRINFO **));
|
||||
* PUBLIC: #endif
|
||||
*/
|
||||
int
|
||||
__os_getaddrinfo(env, nodename, port, servname, hints, res)
|
||||
ENV *env;
|
||||
const char *nodename, *servname;
|
||||
u_int port;
|
||||
const ADDRINFO *hints;
|
||||
ADDRINFO **res;
|
||||
{
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
int ret;
|
||||
|
||||
if ((ret = getaddrinfo(nodename, servname, hints, res)) == 0)
|
||||
return (0);
|
||||
|
||||
__db_errx(env, "%s(%u): host lookup failed: %s",
|
||||
nodename == NULL ? "" : nodename, port,
|
||||
#ifdef DB_WIN32
|
||||
gai_strerrorA(ret));
|
||||
#else
|
||||
gai_strerror(ret));
|
||||
#endif
|
||||
return (__os_posix_err(ret));
|
||||
#else
|
||||
ADDRINFO *answer;
|
||||
struct hostent *hostaddr;
|
||||
struct sockaddr_in sin;
|
||||
u_int32_t tmpaddr;
|
||||
int ret;
|
||||
|
||||
COMPQUIET(hints, NULL);
|
||||
COMPQUIET(servname, NULL);
|
||||
|
||||
/* INADDR_NONE is not defined on Solaris 2.6, 2.7 or 2.8. */
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE ((u_long)0xffffffff)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Basic implementation of IPv4 component of getaddrinfo.
|
||||
* Limited to the functionality used by repmgr.
|
||||
*/
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
if (nodename) {
|
||||
if (nodename[0] == '\0')
|
||||
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
else if ((tmpaddr = inet_addr(nodename)) != INADDR_NONE) {
|
||||
sin.sin_addr.s_addr = tmpaddr;
|
||||
} else {
|
||||
hostaddr = gethostbyname(nodename);
|
||||
if (hostaddr == NULL) {
|
||||
#ifdef DB_WIN32
|
||||
ret = __os_get_neterr();
|
||||
__db_syserr(env, ret,
|
||||
"%s(%u): host lookup failed",
|
||||
nodename == NULL ? "" : nodename, port);
|
||||
return (__os_posix_err(ret));
|
||||
#else
|
||||
/*
|
||||
* Historic UNIX systems used the h_errno
|
||||
* global variable to return gethostbyname
|
||||
* errors. The only function we currently
|
||||
* use that needs h_errno is gethostbyname,
|
||||
* so we deal with it here.
|
||||
*
|
||||
* hstrerror is not available on Solaris 2.6
|
||||
* (it is in libresolv but is a private,
|
||||
* unexported symbol).
|
||||
*/
|
||||
#ifdef HAVE_HSTRERROR
|
||||
__db_errx(env,
|
||||
"%s(%u): host lookup failed: %s",
|
||||
nodename == NULL ? "" : nodename, port,
|
||||
hstrerror(h_errno));
|
||||
#else
|
||||
__db_errx(env,
|
||||
"%s(%u): host lookup failed: %d",
|
||||
nodename == NULL ? "" : nodename, port,
|
||||
h_errno);
|
||||
#endif
|
||||
switch (h_errno) {
|
||||
case HOST_NOT_FOUND:
|
||||
case NO_DATA:
|
||||
return (EHOSTUNREACH);
|
||||
case TRY_AGAIN:
|
||||
return (EAGAIN);
|
||||
case NO_RECOVERY:
|
||||
default:
|
||||
return (EFAULT);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
#endif
|
||||
}
|
||||
memcpy(&(sin.sin_addr),
|
||||
hostaddr->h_addr, (size_t)hostaddr->h_length);
|
||||
}
|
||||
} else /* No host specified. */
|
||||
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
sin.sin_port = htons((u_int16_t)port);
|
||||
|
||||
if ((ret = __os_calloc(env, 1, sizeof(ADDRINFO), &answer)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __os_malloc(env, sizeof(sin), &answer->ai_addr)) != 0) {
|
||||
__os_free(env, answer);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
answer->ai_family = AF_INET;
|
||||
answer->ai_protocol = IPPROTO_TCP;
|
||||
answer->ai_socktype = SOCK_STREAM;
|
||||
answer->ai_addrlen = sizeof(sin);
|
||||
memcpy(answer->ai_addr, &sin, sizeof(sin));
|
||||
*res = answer;
|
||||
|
||||
return (0);
|
||||
#endif /* HAVE_GETADDRINFO */
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_freeaddrinfo --
|
||||
*
|
||||
* PUBLIC: #if defined(HAVE_REPLICATION_THREADS)
|
||||
* PUBLIC: void __os_freeaddrinfo __P((ENV *, ADDRINFO *));
|
||||
* PUBLIC: #endif
|
||||
*/
|
||||
void
|
||||
__os_freeaddrinfo(env, ai)
|
||||
ENV *env;
|
||||
ADDRINFO *ai;
|
||||
{
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
COMPQUIET(env, NULL);
|
||||
|
||||
freeaddrinfo(ai);
|
||||
#else
|
||||
ADDRINFO *next, *tmpaddr;
|
||||
|
||||
for (next = ai; next != NULL; next = tmpaddr) {
|
||||
if (next->ai_canonname != NULL)
|
||||
__os_free(env, next->ai_canonname);
|
||||
|
||||
if (next->ai_addr != NULL)
|
||||
__os_free(env, next->ai_addr);
|
||||
|
||||
tmpaddr = next->ai_next;
|
||||
__os_free(env, next);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
459
os/os_alloc.c
Normal file
459
os/os_alloc.c
Normal file
@@ -0,0 +1,459 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_alloc.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
static void __os_guard __P((ENV *));
|
||||
|
||||
typedef union {
|
||||
size_t size;
|
||||
double align;
|
||||
} db_allocinfo_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* Correct for systems that return NULL when you allocate 0 bytes of memory.
|
||||
* There are several places in DB where we allocate the number of bytes held
|
||||
* by the key/data item, and it can be 0. Correct here so that malloc never
|
||||
* returns a NULL for that reason (which behavior is permitted by ANSI). We
|
||||
* could make these calls macros on non-Alpha architectures (that's where we
|
||||
* saw the problem), but it's probably not worth the autoconf complexity.
|
||||
*
|
||||
* !!!
|
||||
* Correct for systems that don't set errno when malloc and friends fail.
|
||||
*
|
||||
* Out of memory.
|
||||
* We wish to hold the whole sky,
|
||||
* But we never will.
|
||||
*/
|
||||
|
||||
/*
|
||||
* __os_umalloc --
|
||||
* Allocate memory to be used by the application.
|
||||
*
|
||||
* Use, in order of preference, the allocation function specified to the
|
||||
* ENV handle, the allocation function specified as a replacement for
|
||||
* the library malloc, or the library malloc().
|
||||
*
|
||||
* PUBLIC: int __os_umalloc __P((ENV *, size_t, void *));
|
||||
*/
|
||||
int
|
||||
__os_umalloc(env, size, storep)
|
||||
ENV *env;
|
||||
size_t size;
|
||||
void *storep;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int ret;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
|
||||
/* Never allocate 0 bytes -- some C libraries don't like it. */
|
||||
if (size == 0)
|
||||
++size;
|
||||
|
||||
if (dbenv == NULL || dbenv->db_malloc == NULL) {
|
||||
if (DB_GLOBAL(j_malloc) != NULL)
|
||||
*(void **)storep = DB_GLOBAL(j_malloc)(size);
|
||||
else
|
||||
*(void **)storep = malloc(size);
|
||||
if (*(void **)storep == NULL) {
|
||||
/*
|
||||
* Correct error return, see __os_malloc.
|
||||
*/
|
||||
if ((ret = __os_get_errno_ret_zero()) == 0) {
|
||||
ret = ENOMEM;
|
||||
__os_set_errno(ENOMEM);
|
||||
}
|
||||
__db_err(env, ret, "malloc: %lu", (u_long)size);
|
||||
return (ret);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
if ((*(void **)storep = dbenv->db_malloc(size)) == NULL) {
|
||||
__db_errx(env,
|
||||
"user-specified malloc function returned NULL");
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_urealloc --
|
||||
* Allocate memory to be used by the application.
|
||||
*
|
||||
* A realloc(3) counterpart to __os_umalloc's malloc(3).
|
||||
*
|
||||
* PUBLIC: int __os_urealloc __P((ENV *, size_t, void *));
|
||||
*/
|
||||
int
|
||||
__os_urealloc(env, size, storep)
|
||||
ENV *env;
|
||||
size_t size;
|
||||
void *storep;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int ret;
|
||||
void *ptr;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
ptr = *(void **)storep;
|
||||
|
||||
/* Never allocate 0 bytes -- some C libraries don't like it. */
|
||||
if (size == 0)
|
||||
++size;
|
||||
|
||||
if (dbenv == NULL || dbenv->db_realloc == NULL) {
|
||||
if (ptr == NULL)
|
||||
return (__os_umalloc(env, size, storep));
|
||||
|
||||
if (DB_GLOBAL(j_realloc) != NULL)
|
||||
*(void **)storep = DB_GLOBAL(j_realloc)(ptr, size);
|
||||
else
|
||||
*(void **)storep = realloc(ptr, size);
|
||||
if (*(void **)storep == NULL) {
|
||||
/*
|
||||
* Correct errno, see __os_realloc.
|
||||
*/
|
||||
if ((ret = __os_get_errno_ret_zero()) == 0) {
|
||||
ret = ENOMEM;
|
||||
__os_set_errno(ENOMEM);
|
||||
}
|
||||
__db_err(env, ret, "realloc: %lu", (u_long)size);
|
||||
return (ret);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
if ((*(void **)storep = dbenv->db_realloc(ptr, size)) == NULL) {
|
||||
__db_errx(env,
|
||||
"User-specified realloc function returned NULL");
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_ufree --
|
||||
* Free memory used by the application.
|
||||
*
|
||||
* A free(3) counterpart to __os_umalloc's malloc(3).
|
||||
*
|
||||
* PUBLIC: void __os_ufree __P((ENV *, void *));
|
||||
*/
|
||||
void
|
||||
__os_ufree(env, ptr)
|
||||
ENV *env;
|
||||
void *ptr;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
|
||||
if (dbenv != NULL && dbenv->db_free != NULL)
|
||||
dbenv->db_free(ptr);
|
||||
else if (DB_GLOBAL(j_free) != NULL)
|
||||
DB_GLOBAL(j_free)(ptr);
|
||||
else
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_strdup --
|
||||
* The strdup(3) function for DB.
|
||||
*
|
||||
* PUBLIC: int __os_strdup __P((ENV *, const char *, void *));
|
||||
*/
|
||||
int
|
||||
__os_strdup(env, str, storep)
|
||||
ENV *env;
|
||||
const char *str;
|
||||
void *storep;
|
||||
{
|
||||
size_t size;
|
||||
int ret;
|
||||
void *p;
|
||||
|
||||
*(void **)storep = NULL;
|
||||
|
||||
size = strlen(str) + 1;
|
||||
if ((ret = __os_malloc(env, size, &p)) != 0)
|
||||
return (ret);
|
||||
|
||||
memcpy(p, str, size);
|
||||
|
||||
*(void **)storep = p;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_calloc --
|
||||
* The calloc(3) function for DB.
|
||||
*
|
||||
* PUBLIC: int __os_calloc __P((ENV *, size_t, size_t, void *));
|
||||
*/
|
||||
int
|
||||
__os_calloc(env, num, size, storep)
|
||||
ENV *env;
|
||||
size_t num, size;
|
||||
void *storep;
|
||||
{
|
||||
int ret;
|
||||
|
||||
size *= num;
|
||||
if ((ret = __os_malloc(env, size, storep)) != 0)
|
||||
return (ret);
|
||||
|
||||
memset(*(void **)storep, 0, size);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_malloc --
|
||||
* The malloc(3) function for DB.
|
||||
*
|
||||
* PUBLIC: int __os_malloc __P((ENV *, size_t, void *));
|
||||
*/
|
||||
int
|
||||
__os_malloc(env, size, storep)
|
||||
ENV *env;
|
||||
size_t size;
|
||||
void *storep;
|
||||
{
|
||||
int ret;
|
||||
void *p;
|
||||
|
||||
*(void **)storep = NULL;
|
||||
|
||||
/* Never allocate 0 bytes -- some C libraries don't like it. */
|
||||
if (size == 0)
|
||||
++size;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/* Add room for size and a guard byte. */
|
||||
size += sizeof(db_allocinfo_t) + 1;
|
||||
#endif
|
||||
|
||||
if (DB_GLOBAL(j_malloc) != NULL)
|
||||
p = DB_GLOBAL(j_malloc)(size);
|
||||
else
|
||||
p = malloc(size);
|
||||
if (p == NULL) {
|
||||
/*
|
||||
* Some C libraries don't correctly set errno when malloc(3)
|
||||
* fails. We'd like to 0 out errno before calling malloc,
|
||||
* but it turns out that setting errno is quite expensive on
|
||||
* Windows/NT in an MT environment.
|
||||
*/
|
||||
if ((ret = __os_get_errno_ret_zero()) == 0) {
|
||||
ret = ENOMEM;
|
||||
__os_set_errno(ENOMEM);
|
||||
}
|
||||
__db_err(env, ret, "malloc: %lu", (u_long)size);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/* Overwrite memory. */
|
||||
memset(p, CLEAR_BYTE, size);
|
||||
|
||||
/*
|
||||
* Guard bytes: if #DIAGNOSTIC is defined, we allocate an additional
|
||||
* byte after the memory and set it to a special value that we check
|
||||
* for when the memory is free'd.
|
||||
*/
|
||||
((u_int8_t *)p)[size - 1] = CLEAR_BYTE;
|
||||
|
||||
((db_allocinfo_t *)p)->size = size;
|
||||
p = &((db_allocinfo_t *)p)[1];
|
||||
#endif
|
||||
*(void **)storep = p;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_realloc --
|
||||
* The realloc(3) function for DB.
|
||||
*
|
||||
* PUBLIC: int __os_realloc __P((ENV *, size_t, void *));
|
||||
*/
|
||||
int
|
||||
__os_realloc(env, size, storep)
|
||||
ENV *env;
|
||||
size_t size;
|
||||
void *storep;
|
||||
{
|
||||
int ret;
|
||||
void *p, *ptr;
|
||||
|
||||
ptr = *(void **)storep;
|
||||
|
||||
/* Never allocate 0 bytes -- some C libraries don't like it. */
|
||||
if (size == 0)
|
||||
++size;
|
||||
|
||||
/* If we haven't yet allocated anything yet, simply call malloc. */
|
||||
if (ptr == NULL)
|
||||
return (__os_malloc(env, size, storep));
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/* Add room for size and a guard byte. */
|
||||
size += sizeof(db_allocinfo_t) + 1;
|
||||
|
||||
/* Back up to the real beginning */
|
||||
ptr = &((db_allocinfo_t *)ptr)[-1];
|
||||
|
||||
{
|
||||
size_t s;
|
||||
|
||||
s = ((db_allocinfo_t *)ptr)->size;
|
||||
if (((u_int8_t *)ptr)[s - 1] != CLEAR_BYTE)
|
||||
__os_guard(env);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Don't overwrite the original pointer, there are places in DB we
|
||||
* try to continue after realloc fails.
|
||||
*/
|
||||
if (DB_GLOBAL(j_realloc) != NULL)
|
||||
p = DB_GLOBAL(j_realloc)(ptr, size);
|
||||
else
|
||||
p = realloc(ptr, size);
|
||||
if (p == NULL) {
|
||||
/*
|
||||
* Some C libraries don't correctly set errno when malloc(3)
|
||||
* fails. We'd like to 0 out errno before calling malloc,
|
||||
* but it turns out that setting errno is quite expensive on
|
||||
* Windows/NT in an MT environment.
|
||||
*/
|
||||
if ((ret = __os_get_errno_ret_zero()) == 0) {
|
||||
ret = ENOMEM;
|
||||
__os_set_errno(ENOMEM);
|
||||
}
|
||||
__db_err(env, ret, "realloc: %lu", (u_long)size);
|
||||
return (ret);
|
||||
}
|
||||
#ifdef DIAGNOSTIC
|
||||
((u_int8_t *)p)[size - 1] = CLEAR_BYTE; /* Initialize guard byte. */
|
||||
|
||||
((db_allocinfo_t *)p)->size = size;
|
||||
p = &((db_allocinfo_t *)p)[1];
|
||||
#endif
|
||||
|
||||
*(void **)storep = p;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_free --
|
||||
* The free(3) function for DB.
|
||||
*
|
||||
* PUBLIC: void __os_free __P((ENV *, void *));
|
||||
*/
|
||||
void
|
||||
__os_free(env, ptr)
|
||||
ENV *env;
|
||||
void *ptr;
|
||||
{
|
||||
#ifdef DIAGNOSTIC
|
||||
size_t size;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ANSI C requires free(NULL) work. Don't depend on the underlying
|
||||
* library.
|
||||
*/
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* Check that the guard byte (one past the end of the memory) is
|
||||
* still CLEAR_BYTE.
|
||||
*/
|
||||
ptr = &((db_allocinfo_t *)ptr)[-1];
|
||||
size = ((db_allocinfo_t *)ptr)->size;
|
||||
if (((u_int8_t *)ptr)[size - 1] != CLEAR_BYTE)
|
||||
__os_guard(env);
|
||||
|
||||
/* Overwrite memory. */
|
||||
if (size != 0)
|
||||
memset(ptr, CLEAR_BYTE, size);
|
||||
#else
|
||||
COMPQUIET(env, NULL);
|
||||
#endif
|
||||
|
||||
if (DB_GLOBAL(j_free) != NULL)
|
||||
DB_GLOBAL(j_free)(ptr);
|
||||
else
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* __os_guard --
|
||||
* Complain and abort.
|
||||
*/
|
||||
static void
|
||||
__os_guard(env)
|
||||
ENV *env;
|
||||
{
|
||||
__db_errx(env, "Guard byte incorrect during free");
|
||||
__os_abort(env);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __ua_memcpy --
|
||||
* Copy memory to memory without relying on any kind of alignment.
|
||||
*
|
||||
* There are places in DB that we have unaligned data, for example,
|
||||
* when we've stored a structure in a log record as a DBT, and now
|
||||
* we want to look at it. Unfortunately, if you have code like:
|
||||
*
|
||||
* struct a {
|
||||
* int x;
|
||||
* } *p;
|
||||
*
|
||||
* void *func_argument;
|
||||
* int local;
|
||||
*
|
||||
* p = (struct a *)func_argument;
|
||||
* memcpy(&local, p->x, sizeof(local));
|
||||
*
|
||||
* compilers optimize to use inline instructions requiring alignment,
|
||||
* and records in the log don't have any particular alignment. (This
|
||||
* isn't a compiler bug, because it's a structure they're allowed to
|
||||
* assume alignment.)
|
||||
*
|
||||
* Casting the memcpy arguments to (u_int8_t *) appears to work most
|
||||
* of the time, but we've seen examples where it wasn't sufficient
|
||||
* and there's nothing in ANSI C that requires that work.
|
||||
*
|
||||
* PUBLIC: void *__ua_memcpy __P((void *, const void *, size_t));
|
||||
*/
|
||||
void *
|
||||
__ua_memcpy(dst, src, len)
|
||||
void *dst;
|
||||
const void *src;
|
||||
size_t len;
|
||||
{
|
||||
return ((void *)memcpy(dst, src, len));
|
||||
}
|
||||
73
os/os_clock.c
Normal file
73
os/os_clock.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2001,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_clock.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_gettime --
|
||||
* Return the current time-of-day clock in seconds and nanoseconds.
|
||||
*
|
||||
* PUBLIC: void __os_gettime __P((ENV *, db_timespec *, int));
|
||||
*/
|
||||
void
|
||||
__os_gettime(env, tp, monotonic)
|
||||
ENV *env;
|
||||
db_timespec *tp;
|
||||
int monotonic;
|
||||
{
|
||||
const char *sc;
|
||||
int ret;
|
||||
|
||||
#if defined(HAVE_CLOCK_GETTIME)
|
||||
#if defined(HAVE_CLOCK_MONOTONIC)
|
||||
if (monotonic)
|
||||
RETRY_CHK((clock_gettime(
|
||||
CLOCK_MONOTONIC, (struct timespec *)tp)), ret);
|
||||
else
|
||||
#endif
|
||||
RETRY_CHK((clock_gettime(
|
||||
CLOCK_REALTIME, (struct timespec *)tp)), ret);
|
||||
|
||||
RETRY_CHK((clock_gettime(CLOCK_REALTIME, (struct timespec *)tp)), ret);
|
||||
if (ret != 0) {
|
||||
sc = "clock_gettime";
|
||||
goto err;
|
||||
}
|
||||
#elif defined(HAVE_GETTIMEOFDAY)
|
||||
struct timeval v;
|
||||
|
||||
RETRY_CHK((gettimeofday(&v, NULL)), ret);
|
||||
if (ret != 0) {
|
||||
sc = "gettimeofday";
|
||||
goto err;
|
||||
}
|
||||
|
||||
tp->tv_sec = v.tv_sec;
|
||||
tp->tv_nsec = v.tv_usec * NS_PER_US;
|
||||
#elif defined(HAVE_TIME)
|
||||
time_t now;
|
||||
|
||||
RETRY_CHK((time(&now) == (time_t)-1 ? 1 : 0), ret);
|
||||
if (ret != 0) {
|
||||
sc = "time";
|
||||
goto err;
|
||||
}
|
||||
|
||||
tp->tv_sec = now;
|
||||
tp->tv_nsec = 0;
|
||||
#else
|
||||
NO AVAILABLE CLOCK IMPLEMENTATION
|
||||
#endif
|
||||
COMPQUIET(monotonic, 0);
|
||||
return;
|
||||
|
||||
err: __db_syserr(env, ret, "%s", sc);
|
||||
(void)__env_panic(env, __os_posix_err(ret));
|
||||
}
|
||||
70
os/os_config.c
Normal file
70
os/os_config.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1998,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_config.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_fs_notzero --
|
||||
* Return 1 if allocated filesystem blocks are not zeroed.
|
||||
*
|
||||
* PUBLIC: int __os_fs_notzero __P((void));
|
||||
*/
|
||||
int
|
||||
__os_fs_notzero()
|
||||
{
|
||||
/* Most filesystems zero out implicitly created pages. */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_support_direct_io --
|
||||
* Return 1 if we support direct I/O.
|
||||
*
|
||||
* PUBLIC: int __os_support_direct_io __P((void));
|
||||
*/
|
||||
int
|
||||
__os_support_direct_io()
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
|
||||
#ifdef HAVE_O_DIRECT
|
||||
ret = 1;
|
||||
#endif
|
||||
#if defined(HAVE_DIRECTIO) && defined(DIRECTIO_ON)
|
||||
ret = 1;
|
||||
#endif
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_support_db_register --
|
||||
* Return 1 if the system supports DB_REGISTER.
|
||||
*
|
||||
* PUBLIC: int __os_support_db_register __P((void));
|
||||
*/
|
||||
int
|
||||
__os_support_db_register()
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_support_replication --
|
||||
* Return 1 if the system supports replication.
|
||||
*
|
||||
* PUBLIC: int __os_support_replication __P((void));
|
||||
*/
|
||||
int
|
||||
__os_support_replication()
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
47
os/os_cpu.c
Normal file
47
os/os_cpu.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_cpu.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#if defined(HAVE_PSTAT_GETDYNAMIC)
|
||||
#include <sys/pstat.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __os_cpu_count --
|
||||
* Return the number of CPUs.
|
||||
*
|
||||
* PUBLIC: u_int32_t __os_cpu_count __P((void));
|
||||
*/
|
||||
u_int32_t
|
||||
__os_cpu_count()
|
||||
{
|
||||
#if defined(HAVE_PSTAT_GETDYNAMIC)
|
||||
/*
|
||||
* HP/UX.
|
||||
*/
|
||||
struct pst_dynamic psd;
|
||||
|
||||
return ((u_int32_t)pstat_getdynamic(&psd,
|
||||
sizeof(psd), (size_t)1, 0) == -1 ? 1 : psd.psd_proc_cnt);
|
||||
#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
|
||||
/*
|
||||
* Solaris, Linux.
|
||||
*/
|
||||
long nproc;
|
||||
|
||||
nproc = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return ((u_int32_t)(nproc > 1 ? nproc : 1));
|
||||
#else
|
||||
return (1);
|
||||
#endif
|
||||
}
|
||||
47
os/os_ctime.c
Normal file
47
os/os_ctime.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2001,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_ctime.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_ctime --
|
||||
* Format a time-stamp.
|
||||
*
|
||||
* PUBLIC: char *__os_ctime __P((const time_t *, char *));
|
||||
*/
|
||||
char *
|
||||
__os_ctime(tod, time_buf)
|
||||
const time_t *tod;
|
||||
char *time_buf;
|
||||
{
|
||||
time_buf[CTIME_BUFLEN - 1] = '\0';
|
||||
|
||||
/*
|
||||
* The ctime_r interface is the POSIX standard, thread-safe version of
|
||||
* ctime. However, it was implemented in three different ways (with
|
||||
* and without a buffer length argument, and where the buffer length
|
||||
* argument was an int vs. a size_t *). Also, you can't depend on a
|
||||
* return of (char *) from ctime_r, HP-UX 10.XX's version returned an
|
||||
* int.
|
||||
*/
|
||||
#if defined(HAVE_VXWORKS)
|
||||
{
|
||||
size_t buflen = CTIME_BUFLEN;
|
||||
(void)ctime_r(tod, time_buf, &buflen);
|
||||
}
|
||||
#elif defined(HAVE_CTIME_R_3ARG)
|
||||
(void)ctime_r(tod, time_buf, CTIME_BUFLEN);
|
||||
#elif defined(HAVE_CTIME_R)
|
||||
(void)ctime_r(tod, time_buf);
|
||||
#else
|
||||
(void)strncpy(time_buf, ctime(tod), CTIME_BUFLEN - 1);
|
||||
#endif
|
||||
return (time_buf);
|
||||
}
|
||||
119
os/os_dir.c
Normal file
119
os/os_dir.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_dir.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#define __INCLUDE_DIRECTORY 1
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_dirlist --
|
||||
* Return a list of the files in a directory.
|
||||
*
|
||||
* PUBLIC: int __os_dirlist __P((ENV *, const char *, int, char ***, int *));
|
||||
*/
|
||||
int
|
||||
__os_dirlist(env, dir, returndir, namesp, cntp)
|
||||
ENV *env;
|
||||
const char *dir;
|
||||
int returndir, *cntp;
|
||||
char ***namesp;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
struct dirent *dp;
|
||||
DIR *dirp;
|
||||
struct stat sb;
|
||||
int arraysz, cnt, ret;
|
||||
char **names, buf[DB_MAXPATHLEN];
|
||||
|
||||
*namesp = NULL;
|
||||
*cntp = 0;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
|
||||
if (dbenv != NULL &&
|
||||
FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env, "fileops: directory list %s", dir);
|
||||
|
||||
if (DB_GLOBAL(j_dirlist) != NULL)
|
||||
return (DB_GLOBAL(j_dirlist)(dir, namesp, cntp));
|
||||
|
||||
if ((dirp = opendir(CHAR_STAR_CAST dir)) == NULL)
|
||||
return (__os_get_errno());
|
||||
names = NULL;
|
||||
for (arraysz = cnt = 0; (dp = readdir(dirp)) != NULL;) {
|
||||
snprintf(buf, sizeof(buf), "%s/%s", dir, dp->d_name);
|
||||
|
||||
RETRY_CHK(stat(buf, &sb), ret);
|
||||
if (ret != 0) {
|
||||
ret = __os_posix_err(ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* We return regular files, and optionally return directories
|
||||
* (except for dot and dot-dot).
|
||||
*
|
||||
* Shared memory files are of a different type on QNX, and we
|
||||
* return those as well.
|
||||
*/
|
||||
#ifdef HAVE_QNX
|
||||
if (!S_ISREG(sb.st_mode) && !S_TYPEISSHM(&sb)) {
|
||||
#else
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
#endif
|
||||
if (!returndir || !S_ISDIR(sb.st_mode))
|
||||
continue;
|
||||
if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
|
||||
(dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cnt >= arraysz) {
|
||||
arraysz += 100;
|
||||
if ((ret = __os_realloc(env,
|
||||
(u_int)arraysz * sizeof(names[0]), &names)) != 0)
|
||||
goto err;
|
||||
}
|
||||
if ((ret = __os_strdup(env, dp->d_name, &names[cnt])) != 0)
|
||||
goto err;
|
||||
cnt++;
|
||||
}
|
||||
(void)closedir(dirp);
|
||||
|
||||
*namesp = names;
|
||||
*cntp = cnt;
|
||||
return (0);
|
||||
|
||||
err: if (names != NULL)
|
||||
__os_dirfree(env, names, cnt);
|
||||
if (dirp != NULL)
|
||||
(void)closedir(dirp);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_dirfree --
|
||||
* Free the list of files.
|
||||
*
|
||||
* PUBLIC: void __os_dirfree __P((ENV *, char **, int));
|
||||
*/
|
||||
void
|
||||
__os_dirfree(env, names, cnt)
|
||||
ENV *env;
|
||||
char **names;
|
||||
int cnt;
|
||||
{
|
||||
if (DB_GLOBAL(j_dirfree) != NULL)
|
||||
DB_GLOBAL(j_dirfree)(names, cnt);
|
||||
else {
|
||||
while (cnt > 0)
|
||||
__os_free(env, names[--cnt]);
|
||||
__os_free(env, names);
|
||||
}
|
||||
}
|
||||
129
os/os_errno.c
Normal file
129
os/os_errno.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1999,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_errno.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_get_errno_ret_zero --
|
||||
* Return the last system error, including an error of zero.
|
||||
*
|
||||
* PUBLIC: int __os_get_errno_ret_zero __P((void));
|
||||
*/
|
||||
int
|
||||
__os_get_errno_ret_zero()
|
||||
{
|
||||
/* This routine must be able to return the same value repeatedly. */
|
||||
return (errno);
|
||||
}
|
||||
|
||||
/*
|
||||
* We've seen cases where system calls failed but errno was never set. For
|
||||
* that reason, __os_get_errno() and __os_get_syserr set errno to EAGAIN if
|
||||
* it's not already set, to work around the problem. For obvious reasons,
|
||||
* we can only call this function if we know an error has occurred, that
|
||||
* is, we can't test the return for a non-zero value after the get call.
|
||||
*
|
||||
* __os_get_errno --
|
||||
* Return the last ANSI C "errno" value or EAGAIN if the last error
|
||||
* is zero.
|
||||
*
|
||||
* PUBLIC: int __os_get_errno __P((void));
|
||||
*/
|
||||
int
|
||||
__os_get_errno()
|
||||
{
|
||||
/* This routine must be able to return the same value repeatedly. */
|
||||
return (__os_get_syserr());
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* __os_get_neterr --
|
||||
* Return the last network-related error or EAGAIN if the last
|
||||
* error is zero.
|
||||
*
|
||||
* PUBLIC: int __os_get_neterr __P((void));
|
||||
*/
|
||||
int
|
||||
__os_get_neterr()
|
||||
{
|
||||
/* This routine must be able to return the same value repeatedly. */
|
||||
return (__os_get_syserr());
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __os_get_syserr --
|
||||
* Return the last system error or EAGAIN if the last error is zero.
|
||||
*
|
||||
* PUBLIC: int __os_get_syserr __P((void));
|
||||
*/
|
||||
int
|
||||
__os_get_syserr()
|
||||
{
|
||||
/* This routine must be able to return the same value repeatedly. */
|
||||
if (errno == 0)
|
||||
__os_set_errno(EAGAIN);
|
||||
return (errno);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_set_errno --
|
||||
* Set the value of errno.
|
||||
*
|
||||
* PUBLIC: void __os_set_errno __P((int));
|
||||
*/
|
||||
void
|
||||
__os_set_errno(evalue)
|
||||
int evalue;
|
||||
{
|
||||
/*
|
||||
* This routine is called by the compatibility interfaces (DB 1.85,
|
||||
* dbm and hsearch). Force values > 0, that is, not one of DB 2.X
|
||||
* and later's public error returns. If something bad has happened,
|
||||
* default to EFAULT -- a nasty return. Otherwise, default to EINVAL.
|
||||
* As the compatibility APIs aren't included on Windows, the Windows
|
||||
* version of this routine doesn't need this behavior.
|
||||
*/
|
||||
errno =
|
||||
evalue >= 0 ? evalue : (evalue == DB_RUNRECOVERY ? EFAULT : EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_strerror --
|
||||
* Return a string associated with the system error.
|
||||
*
|
||||
* PUBLIC: char *__os_strerror __P((int, char *, size_t));
|
||||
*/
|
||||
char *
|
||||
__os_strerror(error, buf, len)
|
||||
int error;
|
||||
char *buf;
|
||||
size_t len;
|
||||
{
|
||||
/* No translation is needed in the POSIX layer. */
|
||||
(void)strncpy(buf, strerror(error), len - 1);
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_posix_err
|
||||
* Convert a system error to a POSIX error.
|
||||
*
|
||||
* PUBLIC: int __os_posix_err __P((int));
|
||||
*/
|
||||
int
|
||||
__os_posix_err(error)
|
||||
int error;
|
||||
{
|
||||
return (error);
|
||||
}
|
||||
134
os/os_fid.c
Normal file
134
os/os_fid.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_fid.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_fileid --
|
||||
* Return a unique identifier for a file.
|
||||
*
|
||||
* PUBLIC: int __os_fileid __P((ENV *, const char *, int, u_int8_t *));
|
||||
*/
|
||||
int
|
||||
__os_fileid(env, fname, unique_okay, fidp)
|
||||
ENV *env;
|
||||
const char *fname;
|
||||
int unique_okay;
|
||||
u_int8_t *fidp;
|
||||
{
|
||||
pid_t pid;
|
||||
size_t i;
|
||||
u_int32_t tmp;
|
||||
u_int8_t *p;
|
||||
|
||||
#ifdef HAVE_STAT
|
||||
struct stat sb;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The structure of a fileid on a POSIX/UNIX system is:
|
||||
*
|
||||
* ino[4] dev[4] unique-ID[4] serial-counter[4] empty[4].
|
||||
*
|
||||
* For real files, which have a backing inode and device, the first
|
||||
* 8 bytes are filled in and the following bytes are left 0. For
|
||||
* temporary files, the following 12 bytes are filled in.
|
||||
*
|
||||
* Clear the buffer.
|
||||
*/
|
||||
memset(fidp, 0, DB_FILE_ID_LEN);
|
||||
RETRY_CHK((stat(CHAR_STAR_CAST fname, &sb)), ret);
|
||||
if (ret != 0) {
|
||||
__db_syserr(env, ret, "stat: %s", fname);
|
||||
return (__os_posix_err(ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* Nothing is ever big enough -- on Sparc V9, st_ino, st_dev and the
|
||||
* time_t types are all 8 bytes. As DB_FILE_ID_LEN is only 20 bytes,
|
||||
* we convert to a (potentially) smaller fixed-size type and use it.
|
||||
*
|
||||
* We don't worry about byte sexing or the actual variable sizes.
|
||||
*
|
||||
* When this routine is called from the DB access methods, it's only
|
||||
* called once -- whatever ID is generated when a database is created
|
||||
* is stored in the database file's metadata, and that is what is
|
||||
* saved in the mpool region's information to uniquely identify the
|
||||
* file.
|
||||
*
|
||||
* When called from the mpool layer this routine will be called each
|
||||
* time a new thread of control wants to share the file, which makes
|
||||
* things tougher. As far as byte sexing goes, since the mpool region
|
||||
* lives on a single host, there's no issue of that -- the entire
|
||||
* region is byte sex dependent. As far as variable sizes go, we make
|
||||
* the simplifying assumption that 32-bit and 64-bit processes will
|
||||
* get the same 32-bit values if we truncate any returned 64-bit value
|
||||
* to a 32-bit value. When we're called from the mpool layer, though,
|
||||
* we need to be careful not to include anything that isn't
|
||||
* reproducible for a given file, such as the timestamp or serial
|
||||
* number.
|
||||
*/
|
||||
tmp = (u_int32_t)sb.st_ino;
|
||||
for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
|
||||
*fidp++ = *p++;
|
||||
|
||||
tmp = (u_int32_t)sb.st_dev;
|
||||
for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
|
||||
*fidp++ = *p++;
|
||||
#else
|
||||
/*
|
||||
* Use the file name.
|
||||
*
|
||||
* XXX
|
||||
* Cast the first argument, the BREW ARM compiler is unhappy if
|
||||
* we don't.
|
||||
*/
|
||||
(void)strncpy((char *)fidp, fname, DB_FILE_ID_LEN);
|
||||
#endif /* HAVE_STAT */
|
||||
|
||||
if (unique_okay) {
|
||||
/* Add in 32-bits of (hopefully) unique number. */
|
||||
__os_unique_id(env, &tmp);
|
||||
for (p = (u_int8_t *)&tmp, i = sizeof(u_int32_t); i > 0; --i)
|
||||
*fidp++ = *p++;
|
||||
|
||||
/*
|
||||
* Initialize/increment the serial number we use to help
|
||||
* avoid fileid collisions. Note we don't bother with
|
||||
* locking; it's unpleasant to do from down in here, and
|
||||
* if we race on this no real harm will be done, since the
|
||||
* finished fileid has so many other components.
|
||||
*
|
||||
* We use the bottom 32-bits of the process ID, hoping they
|
||||
* are more random than the top 32-bits (should we be on a
|
||||
* machine with 64-bit process IDs).
|
||||
*
|
||||
* We increment by 100000 on each call as a simple way of
|
||||
* randomizing; simply incrementing seems potentially less
|
||||
* useful if pids are also simply incremented, since this
|
||||
* is process-local and we may be one of a set of processes
|
||||
* starting up. 100000 pushes us out of pid space on most
|
||||
* 32-bit platforms, and has few interesting properties in
|
||||
* base 2.
|
||||
*/
|
||||
if (DB_GLOBAL(fid_serial) == 0) {
|
||||
__os_id(env->dbenv, &pid, NULL);
|
||||
DB_GLOBAL(fid_serial) = (u_int32_t)pid;
|
||||
} else
|
||||
DB_GLOBAL(fid_serial) += 100000;
|
||||
|
||||
for (p = (u_int8_t *)
|
||||
&DB_GLOBAL(fid_serial), i = sizeof(u_int32_t); i > 0; --i)
|
||||
*fidp++ = *p++;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
62
os/os_flock.c
Normal file
62
os/os_flock.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_flock.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_fdlock --
|
||||
* Acquire/release a lock on a byte in a file.
|
||||
*
|
||||
* PUBLIC: int __os_fdlock __P((ENV *, DB_FH *, off_t, int, int));
|
||||
*/
|
||||
int
|
||||
__os_fdlock(env, fhp, offset, acquire, nowait)
|
||||
ENV *env;
|
||||
DB_FH *fhp;
|
||||
int acquire, nowait;
|
||||
off_t offset;
|
||||
{
|
||||
#ifdef HAVE_FCNTL
|
||||
DB_ENV *dbenv;
|
||||
struct flock fl;
|
||||
int ret, t_ret;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
|
||||
DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
|
||||
|
||||
if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env,
|
||||
"fileops: flock %s %s offset %lu",
|
||||
fhp->name, acquire ? "acquire": "release", (u_long)offset);
|
||||
|
||||
fl.l_start = offset;
|
||||
fl.l_len = 1;
|
||||
fl.l_type = acquire ? F_WRLCK : F_UNLCK;
|
||||
fl.l_whence = SEEK_SET;
|
||||
|
||||
RETRY_CHK_EINTR_ONLY(
|
||||
(fcntl(fhp->fd, nowait ? F_SETLK : F_SETLKW, &fl)), ret);
|
||||
|
||||
if (ret == 0)
|
||||
return (0);
|
||||
|
||||
if ((t_ret = __os_posix_err(ret)) != EACCES && t_ret != EAGAIN)
|
||||
__db_syserr(env, ret, "fcntl");
|
||||
return (t_ret);
|
||||
#else
|
||||
COMPQUIET(fhp, NULL);
|
||||
COMPQUIET(acquire, 0);
|
||||
COMPQUIET(nowait, 0);
|
||||
COMPQUIET(offset, 0);
|
||||
__db_syserr(env, DB_OPNOTSUP, "advisory file locking unavailable");
|
||||
return (DB_OPNOTSUP);
|
||||
#endif
|
||||
}
|
||||
103
os/os_fsync.c
Normal file
103
os/os_fsync.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_fsync.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
#ifdef HAVE_VXWORKS
|
||||
#include "ioLib.h"
|
||||
|
||||
#define fsync(fd) __vx_fsync(fd)
|
||||
|
||||
int
|
||||
__vx_fsync(fd)
|
||||
int fd;
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The results of ioctl are driver dependent. Some will return the
|
||||
* number of bytes sync'ed. Only if it returns 'ERROR' should we
|
||||
* flag it.
|
||||
*/
|
||||
if ((ret = ioctl(fd, FIOSYNC, 0)) != ERROR)
|
||||
return (0);
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __hp3000s900
|
||||
#define fsync(fd) __mpe_fsync(fd)
|
||||
|
||||
int
|
||||
__mpe_fsync(fd)
|
||||
int fd;
|
||||
{
|
||||
extern FCONTROL(short, short, void *);
|
||||
|
||||
FCONTROL(_MPE_FILENO(fd), 2, NULL); /* Flush the buffers */
|
||||
FCONTROL(_MPE_FILENO(fd), 6, NULL); /* Write the EOF */
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __os_fsync --
|
||||
* Flush a file descriptor.
|
||||
*
|
||||
* PUBLIC: int __os_fsync __P((ENV *, DB_FH *));
|
||||
*/
|
||||
int
|
||||
__os_fsync(env, fhp)
|
||||
ENV *env;
|
||||
DB_FH *fhp;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int ret;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
|
||||
DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
|
||||
|
||||
/*
|
||||
* Do nothing if the file descriptor has been marked as not requiring
|
||||
* any sync to disk.
|
||||
*/
|
||||
if (F_ISSET(fhp, DB_FH_NOSYNC))
|
||||
return (0);
|
||||
|
||||
if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env, "fileops: flush %s", fhp->name);
|
||||
|
||||
if (DB_GLOBAL(j_fsync) != NULL)
|
||||
ret = DB_GLOBAL(j_fsync)(fhp->fd);
|
||||
else {
|
||||
#if defined(F_FULLFSYNC)
|
||||
RETRY_CHK((fcntl(fhp->fd, F_FULLFSYNC, 0)), ret);
|
||||
/*
|
||||
* On OS X, F_FULLSYNC only works on HFS+, so we need to fall
|
||||
* back to regular fsync on other filesystems.
|
||||
*/
|
||||
if (ret == ENOTSUP)
|
||||
RETRY_CHK((fsync(fhp->fd)), ret);
|
||||
#elif defined(HAVE_QNX)
|
||||
ret = __qnx_fsync(fhp);
|
||||
#elif defined(HAVE_FDATASYNC)
|
||||
RETRY_CHK((fdatasync(fhp->fd)), ret);
|
||||
#else
|
||||
RETRY_CHK((fsync(fhp->fd)), ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
__db_syserr(env, ret, "fsync");
|
||||
ret = __os_posix_err(ret);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
58
os/os_getenv.c
Normal file
58
os/os_getenv.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_getenv.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_getenv --
|
||||
* Retrieve an environment variable.
|
||||
*
|
||||
* PUBLIC: int __os_getenv __P((ENV *, const char *, char **, size_t));
|
||||
*/
|
||||
int
|
||||
__os_getenv(env, name, bpp, buflen)
|
||||
ENV *env;
|
||||
const char *name;
|
||||
char **bpp;
|
||||
size_t buflen;
|
||||
{
|
||||
/*
|
||||
* If we have getenv, there's a value and the buffer is large enough:
|
||||
* copy value into the pointer, return 0
|
||||
* If we have getenv, there's a value and the buffer is too short:
|
||||
* set pointer to NULL, return EINVAL
|
||||
* If we have getenv and there's no value:
|
||||
* set pointer to NULL, return 0
|
||||
* If we don't have getenv:
|
||||
* set pointer to NULL, return 0
|
||||
*/
|
||||
#ifdef HAVE_GETENV
|
||||
char *p;
|
||||
|
||||
if ((p = getenv(name)) != NULL) {
|
||||
if (strlen(p) < buflen) {
|
||||
(void)strcpy(*bpp, p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
*bpp = NULL;
|
||||
__db_errx(env,
|
||||
"%s: buffer too small to hold environment variable %s",
|
||||
name, p);
|
||||
return (EINVAL);
|
||||
}
|
||||
#else
|
||||
COMPQUIET(env, NULL);
|
||||
COMPQUIET(name, NULL);
|
||||
COMPQUIET(buflen, 0);
|
||||
#endif
|
||||
*bpp = NULL;
|
||||
return (0);
|
||||
}
|
||||
241
os/os_handle.c
Normal file
241
os/os_handle.c
Normal file
@@ -0,0 +1,241 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1998,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_handle.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_openhandle --
|
||||
* Open a file, using POSIX 1003.1 open flags.
|
||||
*
|
||||
* PUBLIC: int __os_openhandle
|
||||
* PUBLIC: __P((ENV *, const char *, int, int, DB_FH **));
|
||||
*/
|
||||
int
|
||||
__os_openhandle(env, name, flags, mode, fhpp)
|
||||
ENV *env;
|
||||
const char *name;
|
||||
int flags, mode;
|
||||
DB_FH **fhpp;
|
||||
{
|
||||
DB_FH *fhp;
|
||||
u_int nrepeat, retries;
|
||||
int fcntl_flags, ret;
|
||||
#ifdef HAVE_VXWORKS
|
||||
int newflags;
|
||||
#endif
|
||||
/*
|
||||
* Allocate the file handle and copy the file name. We generally only
|
||||
* use the name for verbose or error messages, but on systems where we
|
||||
* can't unlink temporary files immediately, we use the name to unlink
|
||||
* the temporary file when the file handle is closed.
|
||||
*
|
||||
* Lock the ENV handle and insert the new file handle on the list.
|
||||
*/
|
||||
if ((ret = __os_calloc(env, 1, sizeof(DB_FH), &fhp)) != 0)
|
||||
return (ret);
|
||||
if ((ret = __os_strdup(env, name, &fhp->name)) != 0)
|
||||
goto err;
|
||||
if (env != NULL) {
|
||||
MUTEX_LOCK(env, env->mtx_env);
|
||||
TAILQ_INSERT_TAIL(&env->fdlist, fhp, q);
|
||||
MUTEX_UNLOCK(env, env->mtx_env);
|
||||
F_SET(fhp, DB_FH_ENVLINK);
|
||||
}
|
||||
|
||||
/* If the application specified an interface, use it. */
|
||||
if (DB_GLOBAL(j_open) != NULL) {
|
||||
if ((fhp->fd = DB_GLOBAL(j_open)(name, flags, mode)) == -1) {
|
||||
ret = __os_posix_err(__os_get_syserr());
|
||||
goto err;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
retries = 0;
|
||||
for (nrepeat = 1; nrepeat < 4; ++nrepeat) {
|
||||
ret = 0;
|
||||
#ifdef HAVE_VXWORKS
|
||||
/*
|
||||
* VxWorks does not support O_CREAT on open, you have to use
|
||||
* creat() instead. (It does not support O_EXCL or O_TRUNC
|
||||
* either, even though they are defined "for future support".)
|
||||
* We really want the POSIX behavior that if O_CREAT is set,
|
||||
* we open if it exists, or create it if it doesn't exist.
|
||||
* If O_CREAT is specified, single thread and try to open the
|
||||
* file. If successful, and O_EXCL return EEXIST. If
|
||||
* unsuccessful call creat and then end single threading.
|
||||
*/
|
||||
if (LF_ISSET(O_CREAT)) {
|
||||
DB_BEGIN_SINGLE_THREAD;
|
||||
newflags = flags & ~(O_CREAT | O_EXCL);
|
||||
if ((fhp->fd = open(name, newflags, mode)) != -1) {
|
||||
/*
|
||||
* We need to mark the file opened at this
|
||||
* point so that if we get any error below
|
||||
* we will properly close the fd we just
|
||||
* opened on the error path.
|
||||
*/
|
||||
F_SET(fhp, DB_FH_OPENED);
|
||||
if (LF_ISSET(O_EXCL)) {
|
||||
/*
|
||||
* If we get here, want O_EXCL create,
|
||||
* and the file exists. Close and
|
||||
* return EEXISTS.
|
||||
*/
|
||||
DB_END_SINGLE_THREAD;
|
||||
ret = EEXIST;
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
* XXX
|
||||
* Assume any error means non-existence.
|
||||
* Unfortunately return values (even for
|
||||
* non-existence) are driver specific so
|
||||
* there is no single error we can use to
|
||||
* verify we truly got the equivalent of
|
||||
* ENOENT.
|
||||
*/
|
||||
} else
|
||||
fhp->fd = creat(name, newflags);
|
||||
DB_END_SINGLE_THREAD;
|
||||
} else
|
||||
/* FALLTHROUGH */
|
||||
#endif
|
||||
#ifdef __VMS
|
||||
/*
|
||||
* !!!
|
||||
* Open with full sharing on VMS.
|
||||
*
|
||||
* We use these flags because they are the ones set by the VMS
|
||||
* CRTL mmap() call when it opens a file, and we have to be
|
||||
* able to open files that mmap() has previously opened, e.g.,
|
||||
* when we're joining already existing DB regions.
|
||||
*/
|
||||
fhp->fd = open(name, flags, mode, "shr=get,put,upd,del,upi");
|
||||
#else
|
||||
fhp->fd = open(name, flags, mode);
|
||||
#endif
|
||||
if (fhp->fd != -1) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ret = __os_posix_err(__os_get_syserr())) {
|
||||
case EMFILE:
|
||||
case ENFILE:
|
||||
case ENOSPC:
|
||||
/*
|
||||
* If it's a "temporary" error, we retry up to 3 times,
|
||||
* waiting up to 12 seconds. While it's not a problem
|
||||
* if we can't open a database, an inability to open a
|
||||
* log file is cause for serious dismay.
|
||||
*/
|
||||
__os_yield(env, nrepeat * 2, 0);
|
||||
break;
|
||||
case EAGAIN:
|
||||
case EBUSY:
|
||||
case EINTR:
|
||||
/*
|
||||
* If an EAGAIN, EBUSY or EINTR, retry immediately for
|
||||
* DB_RETRY times.
|
||||
*/
|
||||
if (++retries < DB_RETRY)
|
||||
--nrepeat;
|
||||
break;
|
||||
default:
|
||||
/* Open is silent on error. */
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
#if defined(HAVE_FCNTL_F_SETFD)
|
||||
/* Deny file descriptor access to any child process. */
|
||||
if ((fcntl_flags = fcntl(fhp->fd, F_GETFD)) == -1 ||
|
||||
fcntl(fhp->fd, F_SETFD, fcntl_flags | FD_CLOEXEC) == -1) {
|
||||
ret = __os_get_syserr();
|
||||
__db_syserr(env, ret, "fcntl(F_SETFD)");
|
||||
ret = __os_posix_err(ret);
|
||||
goto err;
|
||||
}
|
||||
#else
|
||||
COMPQUIET(fcntl_flags, 0);
|
||||
#endif
|
||||
|
||||
done: F_SET(fhp, DB_FH_OPENED);
|
||||
*fhpp = fhp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
err: (void)__os_closehandle(env, fhp);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_closehandle --
|
||||
* Close a file.
|
||||
*
|
||||
* PUBLIC: int __os_closehandle __P((ENV *, DB_FH *));
|
||||
*/
|
||||
int
|
||||
__os_closehandle(env, fhp)
|
||||
ENV *env;
|
||||
DB_FH *fhp;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
|
||||
/*
|
||||
* If we linked the DB_FH handle into the ENV, it needs to be
|
||||
* unlinked.
|
||||
*/
|
||||
DB_ASSERT(env, env != NULL || !F_ISSET(fhp, DB_FH_ENVLINK));
|
||||
|
||||
if (env != NULL) {
|
||||
dbenv = env->dbenv;
|
||||
if (fhp->name != NULL && FLD_ISSET(
|
||||
dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env, "fileops: close %s", fhp->name);
|
||||
|
||||
if (F_ISSET(fhp, DB_FH_ENVLINK)) {
|
||||
/*
|
||||
* Lock the ENV handle and remove this file
|
||||
* handle from the list.
|
||||
*/
|
||||
MUTEX_LOCK(env, env->mtx_env);
|
||||
TAILQ_REMOVE(&env->fdlist, fhp, q);
|
||||
MUTEX_UNLOCK(env, env->mtx_env);
|
||||
}
|
||||
}
|
||||
|
||||
/* Discard any underlying system file reference. */
|
||||
if (F_ISSET(fhp, DB_FH_OPENED)) {
|
||||
if (DB_GLOBAL(j_close) != NULL)
|
||||
ret = DB_GLOBAL(j_close)(fhp->fd);
|
||||
else
|
||||
RETRY_CHK((close(fhp->fd)), ret);
|
||||
if (ret != 0) {
|
||||
__db_syserr(env, ret, "close");
|
||||
ret = __os_posix_err(ret);
|
||||
}
|
||||
}
|
||||
|
||||
/* Unlink the file if we haven't already done so. */
|
||||
if (F_ISSET(fhp, DB_FH_UNLINK))
|
||||
(void)__os_unlink(env, fhp->name, 0);
|
||||
|
||||
if (fhp->name != NULL)
|
||||
__os_free(env, fhp->name);
|
||||
__os_free(env, fhp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
594
os/os_map.c
Normal file
594
os/os_map.c
Normal file
@@ -0,0 +1,594 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_map.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#ifdef HAVE_MMAP
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SHMGET
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
static int __os_map __P((ENV *, char *, DB_FH *, size_t, int, int, void **));
|
||||
#endif
|
||||
#ifdef HAVE_SHMGET
|
||||
static int __shm_mode __P((ENV *));
|
||||
#else
|
||||
static int __no_system_mem __P((ENV *));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __os_attach --
|
||||
* Create/join a shared memory region.
|
||||
*
|
||||
* PUBLIC: int __os_attach __P((ENV *, REGINFO *, REGION *));
|
||||
*/
|
||||
int
|
||||
__os_attach(env, infop, rp)
|
||||
ENV *env;
|
||||
REGINFO *infop;
|
||||
REGION *rp;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int create_ok, ret;
|
||||
|
||||
/*
|
||||
* We pass a DB_ENV handle to the user's replacement map function,
|
||||
* so there must be a valid handle.
|
||||
*/
|
||||
DB_ASSERT(env, env != NULL && env->dbenv != NULL);
|
||||
dbenv = env->dbenv;
|
||||
|
||||
if (DB_GLOBAL(j_region_map) != NULL) {
|
||||
/*
|
||||
* We have to find out if the region is being created. Ask
|
||||
* the underlying map function, and use the REGINFO structure
|
||||
* to pass that information back to our caller.
|
||||
*/
|
||||
create_ok = F_ISSET(infop, REGION_CREATE) ? 1 : 0;
|
||||
ret = DB_GLOBAL(j_region_map)
|
||||
(dbenv, infop->name, rp->size, &create_ok, &infop->addr);
|
||||
if (create_ok)
|
||||
F_SET(infop, REGION_CREATE);
|
||||
else
|
||||
F_CLR(infop, REGION_CREATE);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if (F_ISSET(env, ENV_SYSTEM_MEM)) {
|
||||
/*
|
||||
* If the region is in system memory on UNIX, we use shmget(2).
|
||||
*
|
||||
* !!!
|
||||
* There exist spinlocks that don't work in shmget memory, e.g.,
|
||||
* the HP/UX msemaphore interface. If we don't have locks that
|
||||
* will work in shmget memory, we better be private and not be
|
||||
* threaded. If we reach this point, we know we're public, so
|
||||
* it's an error.
|
||||
*/
|
||||
#if defined(HAVE_MUTEX_HPPA_MSEM_INIT)
|
||||
__db_errx(env,
|
||||
"architecture does not support locks inside system shared memory");
|
||||
return (EINVAL);
|
||||
#endif
|
||||
#if defined(HAVE_SHMGET)
|
||||
{
|
||||
key_t segid;
|
||||
int id, mode;
|
||||
|
||||
/*
|
||||
* We could potentially create based on REGION_CREATE_OK, but
|
||||
* that's dangerous -- we might get crammed in sideways if
|
||||
* some of the expected regions exist but others do not. Also,
|
||||
* if the requested size differs from an existing region's
|
||||
* actual size, then all sorts of nasty things can happen.
|
||||
* Basing create solely on REGION_CREATE is much safer -- a
|
||||
* recovery will get us straightened out.
|
||||
*/
|
||||
if (F_ISSET(infop, REGION_CREATE)) {
|
||||
/*
|
||||
* The application must give us a base System V IPC key
|
||||
* value. Adjust that value based on the region's ID,
|
||||
* and correct so the user's original value appears in
|
||||
* the ipcs output.
|
||||
*/
|
||||
if (dbenv->shm_key == INVALID_REGION_SEGID) {
|
||||
__db_errx(env,
|
||||
"no base system shared memory ID specified");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* The BDB API takes a "long" as the base segment ID,
|
||||
* then adds an unsigned 32-bit value and stores it
|
||||
* in a key_t. Wrong, admittedly, but not worth an
|
||||
* API change to fix.
|
||||
*/
|
||||
segid = (key_t)
|
||||
((u_long)dbenv->shm_key + (infop->id - 1));
|
||||
|
||||
/*
|
||||
* If map to an existing region, assume the application
|
||||
* crashed and we're restarting. Delete the old region
|
||||
* and re-try. If that fails, return an error, the
|
||||
* application will have to select a different segment
|
||||
* ID or clean up some other way.
|
||||
*/
|
||||
if ((id = shmget(segid, 0, 0)) != -1) {
|
||||
(void)shmctl(id, IPC_RMID, NULL);
|
||||
if ((id = shmget(segid, 0, 0)) != -1) {
|
||||
__db_errx(env,
|
||||
"shmget: key: %ld: shared system memory region already exists",
|
||||
(long)segid);
|
||||
return (EAGAIN);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the DbEnv::open method file mode permissions to
|
||||
* shmget call permissions.
|
||||
*/
|
||||
mode = IPC_CREAT | __shm_mode(env);
|
||||
if ((id = shmget(segid, rp->size, mode)) == -1) {
|
||||
ret = __os_get_syserr();
|
||||
__db_syserr(env, ret,
|
||||
"shmget: key: %ld: unable to create shared system memory region",
|
||||
(long)segid);
|
||||
return (__os_posix_err(ret));
|
||||
}
|
||||
rp->segid = id;
|
||||
} else
|
||||
id = rp->segid;
|
||||
|
||||
if ((infop->addr = shmat(id, NULL, 0)) == (void *)-1) {
|
||||
infop->addr = NULL;
|
||||
ret = __os_get_syserr();
|
||||
__db_syserr(env, ret,
|
||||
"shmat: id %d: unable to attach to shared system memory region", id);
|
||||
return (__os_posix_err(ret));
|
||||
}
|
||||
|
||||
/* Optionally lock the memory down. */
|
||||
if (F_ISSET(env, ENV_LOCKDOWN)) {
|
||||
#ifdef HAVE_SHMCTL_SHM_LOCK
|
||||
ret = shmctl(
|
||||
id, SHM_LOCK, NULL) == 0 ? 0 : __os_get_syserr();
|
||||
#else
|
||||
ret = DB_OPNOTSUP;
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
__db_syserr(env, ret,
|
||||
"shmctl/SHM_LOCK: id %d: unable to lock down shared memory region", id);
|
||||
return (__os_posix_err(ret));
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
#else
|
||||
return (__no_system_mem(env));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
{
|
||||
DB_FH *fhp;
|
||||
|
||||
fhp = NULL;
|
||||
|
||||
/*
|
||||
* Try to open/create the shared region file. We DO NOT need to ensure
|
||||
* that multiple threads/processes attempting to simultaneously create
|
||||
* the region are properly ordered, our caller has already taken care
|
||||
* of that.
|
||||
*/
|
||||
if ((ret = __os_open(env, infop->name, 0,
|
||||
DB_OSO_REGION |
|
||||
(F_ISSET(infop, REGION_CREATE_OK) ? DB_OSO_CREATE : 0),
|
||||
env->db_mode, &fhp)) != 0)
|
||||
__db_err(env, ret, "%s", infop->name);
|
||||
|
||||
/*
|
||||
* If we created the file, grow it to its full size before mapping
|
||||
* it in. We really want to avoid touching the buffer cache after
|
||||
* mmap(2) is called, doing anything else confuses the hell out of
|
||||
* systems without merged VM/buffer cache systems, or, more to the
|
||||
* point, *badly* merged VM/buffer cache systems.
|
||||
*/
|
||||
if (ret == 0 && F_ISSET(infop, REGION_CREATE)) {
|
||||
if (F_ISSET(dbenv, DB_ENV_REGION_INIT))
|
||||
ret = __db_file_write(env, fhp,
|
||||
rp->size / MEGABYTE, rp->size % MEGABYTE, 0x00);
|
||||
else
|
||||
ret = __db_file_extend(env, fhp, rp->size);
|
||||
}
|
||||
|
||||
/* Map the file in. */
|
||||
if (ret == 0)
|
||||
ret = __os_map(env,
|
||||
infop->name, fhp, rp->size, 1, 0, &infop->addr);
|
||||
|
||||
if (fhp != NULL)
|
||||
(void)__os_closehandle(env, fhp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
#else
|
||||
COMPQUIET(infop, NULL);
|
||||
COMPQUIET(rp, NULL);
|
||||
__db_errx(env,
|
||||
"architecture lacks mmap(2), shared environments not possible");
|
||||
return (DB_OPNOTSUP);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_detach --
|
||||
* Detach from a shared memory region.
|
||||
*
|
||||
* PUBLIC: int __os_detach __P((ENV *, REGINFO *, int));
|
||||
*/
|
||||
int
|
||||
__os_detach(env, infop, destroy)
|
||||
ENV *env;
|
||||
REGINFO *infop;
|
||||
int destroy;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
REGION *rp;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We pass a DB_ENV handle to the user's replacement unmap function,
|
||||
* so there must be a valid handle.
|
||||
*/
|
||||
DB_ASSERT(env, env != NULL && env->dbenv != NULL);
|
||||
dbenv = env->dbenv;
|
||||
|
||||
rp = infop->rp;
|
||||
|
||||
/* If the user replaced the unmap call, call through their interface. */
|
||||
if (DB_GLOBAL(j_region_unmap) != NULL)
|
||||
return (DB_GLOBAL(j_region_unmap)(dbenv, infop->addr));
|
||||
|
||||
if (F_ISSET(env, ENV_SYSTEM_MEM)) {
|
||||
#ifdef HAVE_SHMGET
|
||||
int segid;
|
||||
|
||||
/*
|
||||
* We may be about to remove the memory referenced by rp,
|
||||
* save the segment ID, and (optionally) wipe the original.
|
||||
*/
|
||||
segid = rp->segid;
|
||||
if (destroy)
|
||||
rp->segid = INVALID_REGION_SEGID;
|
||||
|
||||
if (shmdt(infop->addr) != 0) {
|
||||
ret = __os_get_syserr();
|
||||
__db_syserr(env, ret, "shmdt");
|
||||
return (__os_posix_err(ret));
|
||||
}
|
||||
|
||||
if (destroy && shmctl(segid, IPC_RMID,
|
||||
NULL) != 0 && (ret = __os_get_syserr()) != EINVAL) {
|
||||
__db_syserr(env, ret,
|
||||
"shmctl: id %d: unable to delete system shared memory region",
|
||||
segid);
|
||||
return (__os_posix_err(ret));
|
||||
}
|
||||
|
||||
return (0);
|
||||
#else
|
||||
return (__no_system_mem(env));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
#ifdef HAVE_MUNLOCK
|
||||
if (F_ISSET(env, ENV_LOCKDOWN))
|
||||
(void)munlock(infop->addr, rp->size);
|
||||
#endif
|
||||
if (munmap(infop->addr, rp->size) != 0) {
|
||||
ret = __os_get_syserr();
|
||||
__db_syserr(env, ret, "munmap");
|
||||
return (__os_posix_err(ret));
|
||||
}
|
||||
|
||||
if (destroy && (ret = __os_unlink(env, infop->name, 1)) != 0)
|
||||
return (ret);
|
||||
|
||||
return (0);
|
||||
#else
|
||||
COMPQUIET(destroy, 0);
|
||||
COMPQUIET(ret, 0);
|
||||
return (EINVAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_mapfile --
|
||||
* Map in a shared memory file.
|
||||
*
|
||||
* PUBLIC: int __os_mapfile __P((ENV *, char *, DB_FH *, size_t, int, void **));
|
||||
*/
|
||||
int
|
||||
__os_mapfile(env, path, fhp, len, is_rdonly, addrp)
|
||||
ENV *env;
|
||||
char *path;
|
||||
DB_FH *fhp;
|
||||
int is_rdonly;
|
||||
size_t len;
|
||||
void **addrp;
|
||||
{
|
||||
#if defined(HAVE_MMAP) && !defined(HAVE_QNX)
|
||||
DB_ENV *dbenv;
|
||||
|
||||
/* If the user replaced the map call, call through their interface. */
|
||||
if (DB_GLOBAL(j_file_map) != NULL) {
|
||||
/*
|
||||
* We pass a DB_ENV handle to the user's replacement map
|
||||
* function, so there must be a valid handle.
|
||||
*/
|
||||
DB_ASSERT(env, env != NULL && env->dbenv != NULL);
|
||||
dbenv = env->dbenv;
|
||||
|
||||
return (
|
||||
DB_GLOBAL(j_file_map)(dbenv, path, len, is_rdonly, addrp));
|
||||
}
|
||||
|
||||
return (__os_map(env, path, fhp, len, 0, is_rdonly, addrp));
|
||||
#else
|
||||
COMPQUIET(env, NULL);
|
||||
COMPQUIET(path, NULL);
|
||||
COMPQUIET(fhp, NULL);
|
||||
COMPQUIET(is_rdonly, 0);
|
||||
COMPQUIET(len, 0);
|
||||
COMPQUIET(addrp, NULL);
|
||||
return (DB_OPNOTSUP);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_unmapfile --
|
||||
* Unmap the shared memory file.
|
||||
*
|
||||
* PUBLIC: int __os_unmapfile __P((ENV *, void *, size_t));
|
||||
*/
|
||||
int
|
||||
__os_unmapfile(env, addr, len)
|
||||
ENV *env;
|
||||
void *addr;
|
||||
size_t len;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We pass a DB_ENV handle to the user's replacement unmap function,
|
||||
* so there must be a valid handle.
|
||||
*/
|
||||
DB_ASSERT(env, env != NULL && env->dbenv != NULL);
|
||||
dbenv = env->dbenv;
|
||||
|
||||
if (FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env, "fileops: munmap");
|
||||
|
||||
/* If the user replaced the map call, call through their interface. */
|
||||
if (DB_GLOBAL(j_file_unmap) != NULL)
|
||||
return (DB_GLOBAL(j_file_unmap)(dbenv, addr));
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
#ifdef HAVE_MUNLOCK
|
||||
if (F_ISSET(env, ENV_LOCKDOWN))
|
||||
RETRY_CHK((munlock(addr, len)), ret);
|
||||
/*
|
||||
* !!!
|
||||
* The return value is ignored.
|
||||
*/
|
||||
#else
|
||||
COMPQUIET(env, NULL);
|
||||
#endif
|
||||
RETRY_CHK((munmap(addr, len)), ret);
|
||||
ret = __os_posix_err(ret);
|
||||
#else
|
||||
COMPQUIET(env, NULL);
|
||||
ret = EINVAL;
|
||||
#endif
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
/*
|
||||
* __os_map --
|
||||
* Call the mmap(2) function.
|
||||
*/
|
||||
static int
|
||||
__os_map(env, path, fhp, len, is_region, is_rdonly, addrp)
|
||||
ENV *env;
|
||||
char *path;
|
||||
DB_FH *fhp;
|
||||
int is_region, is_rdonly;
|
||||
size_t len;
|
||||
void **addrp;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int flags, prot, ret;
|
||||
void *p;
|
||||
|
||||
/*
|
||||
* We pass a DB_ENV handle to the user's replacement map function,
|
||||
* so there must be a valid handle.
|
||||
*/
|
||||
DB_ASSERT(env, env != NULL && env->dbenv != NULL);
|
||||
dbenv = env->dbenv;
|
||||
|
||||
if (FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env, "fileops: mmap %s", path);
|
||||
|
||||
DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
|
||||
|
||||
/*
|
||||
* If it's read-only, it's private, and if it's not, it's shared.
|
||||
* Don't bother with an additional parameter.
|
||||
*/
|
||||
flags = is_rdonly ? MAP_PRIVATE : MAP_SHARED;
|
||||
|
||||
#ifdef MAP_FILE
|
||||
/*
|
||||
* Historically, MAP_FILE was required for mapping regular files,
|
||||
* even though it was the default. Some systems have it, some
|
||||
* don't, some that have it set it to 0.
|
||||
*/
|
||||
flags |= MAP_FILE;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* I know of no systems that implement the flag to tell the system
|
||||
* that the region contains semaphores, but it's not an unreasonable
|
||||
* thing to do, and has been part of the design since forever. I
|
||||
* don't think anyone will object, but don't set it for read-only
|
||||
* files, it doesn't make sense.
|
||||
*/
|
||||
#ifdef MAP_HASSEMAPHORE
|
||||
if (is_region && !is_rdonly)
|
||||
flags |= MAP_HASSEMAPHORE;
|
||||
#else
|
||||
COMPQUIET(is_region, 0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FreeBSD:
|
||||
* Causes data dirtied via this VM map to be flushed to physical media
|
||||
* only when necessary (usually by the pager) rather then gratuitously.
|
||||
* Typically this prevents the update daemons from flushing pages
|
||||
* dirtied through such maps and thus allows efficient sharing of
|
||||
* memory across unassociated processes using a file-backed shared
|
||||
* memory map.
|
||||
*/
|
||||
#ifdef MAP_NOSYNC
|
||||
flags |= MAP_NOSYNC;
|
||||
#endif
|
||||
|
||||
prot = PROT_READ | (is_rdonly ? 0 : PROT_WRITE);
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Work around a bug in the VMS V7.1 mmap() implementation. To map
|
||||
* a file into memory on VMS it needs to be opened in a certain way,
|
||||
* originally. To get the file opened in that certain way, the VMS
|
||||
* mmap() closes the file and re-opens it. When it does this, it
|
||||
* doesn't flush any caches out to disk before closing. The problem
|
||||
* this causes us is that when the memory cache doesn't get written
|
||||
* out, the file isn't big enough to match the memory chunk and the
|
||||
* mmap() call fails. This call to fsync() fixes the problem. DEC
|
||||
* thinks this isn't a bug because of language in XPG5 discussing user
|
||||
* responsibility for on-disk and in-memory synchronization.
|
||||
*/
|
||||
#ifdef VMS
|
||||
if (__os_fsync(env, fhp) == -1)
|
||||
return (__os_posix_err(__os_get_syserr()));
|
||||
#endif
|
||||
|
||||
/* MAP_FAILED was not defined in early mmap implementations. */
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED -1
|
||||
#endif
|
||||
if ((p = mmap(NULL,
|
||||
len, prot, flags, fhp->fd, (off_t)0)) == (void *)MAP_FAILED) {
|
||||
ret = __os_get_syserr();
|
||||
__db_syserr(env, ret, "mmap");
|
||||
return (__os_posix_err(ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* If it's a region, we want to make sure that the memory isn't paged.
|
||||
* For example, Solaris will page large mpools because it thinks that
|
||||
* I/O buffer memory is more important than we are. The mlock system
|
||||
* call may or may not succeed (mlock is restricted to the super-user
|
||||
* on some systems). Currently, the only other use of mmap in DB is
|
||||
* to map read-only databases -- we don't want them paged, either, so
|
||||
* the call isn't conditional.
|
||||
*/
|
||||
if (F_ISSET(env, ENV_LOCKDOWN)) {
|
||||
#ifdef HAVE_MLOCK
|
||||
ret = mlock(p, len) == 0 ? 0 : __os_get_syserr();
|
||||
#else
|
||||
ret = DB_OPNOTSUP;
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
__db_syserr(env, ret, "mlock");
|
||||
return (__os_posix_err(ret));
|
||||
}
|
||||
}
|
||||
|
||||
*addrp = p;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SHMGET
|
||||
#ifndef SHM_R
|
||||
#define SHM_R 0400
|
||||
#endif
|
||||
#ifndef SHM_W
|
||||
#define SHM_W 0200
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __shm_mode --
|
||||
* Map the DbEnv::open method file mode permissions to shmget call
|
||||
* permissions.
|
||||
*/
|
||||
static int
|
||||
__shm_mode(env)
|
||||
ENV *env;
|
||||
{
|
||||
int mode;
|
||||
|
||||
/* Default to r/w owner, r/w group. */
|
||||
if (env->db_mode == 0)
|
||||
return (SHM_R | SHM_W | SHM_R >> 3 | SHM_W >> 3);
|
||||
|
||||
mode = 0;
|
||||
if (env->db_mode & S_IRUSR)
|
||||
mode |= SHM_R;
|
||||
if (env->db_mode & S_IWUSR)
|
||||
mode |= SHM_W;
|
||||
if (env->db_mode & S_IRGRP)
|
||||
mode |= SHM_R >> 3;
|
||||
if (env->db_mode & S_IWGRP)
|
||||
mode |= SHM_W >> 3;
|
||||
if (env->db_mode & S_IROTH)
|
||||
mode |= SHM_R >> 6;
|
||||
if (env->db_mode & S_IWOTH)
|
||||
mode |= SHM_W >> 6;
|
||||
return (mode);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* __no_system_mem --
|
||||
* No system memory environments error message.
|
||||
*/
|
||||
static int
|
||||
__no_system_mem(env)
|
||||
ENV *env;
|
||||
{
|
||||
__db_errx(env,
|
||||
"architecture doesn't support environments in system memory");
|
||||
return (DB_OPNOTSUP);
|
||||
}
|
||||
#endif /* HAVE_SHMGET */
|
||||
51
os/os_mkdir.c
Normal file
51
os/os_mkdir.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_mkdir.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_mkdir --
|
||||
* Create a directory.
|
||||
*
|
||||
* PUBLIC: int __os_mkdir __P((ENV *, const char *, int));
|
||||
*/
|
||||
int
|
||||
__os_mkdir(env, name, mode)
|
||||
ENV *env;
|
||||
const char *name;
|
||||
int mode;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int ret;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
if (dbenv != NULL &&
|
||||
FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env, "fileops: mkdir %s", name);
|
||||
|
||||
/* Make the directory, with paranoid permissions. */
|
||||
#if defined(HAVE_VXWORKS)
|
||||
RETRY_CHK((mkdir(CHAR_STAR_CAST name)), ret);
|
||||
#else
|
||||
RETRY_CHK((mkdir(name, DB_MODE_700)), ret);
|
||||
#endif
|
||||
if (ret != 0)
|
||||
return (__os_posix_err(ret));
|
||||
|
||||
/* Set the absolute permissions, if specified. */
|
||||
#if !defined(HAVE_VXWORKS)
|
||||
if (mode != 0) {
|
||||
RETRY_CHK((chmod(name, mode)), ret);
|
||||
if (ret != 0)
|
||||
ret = __os_posix_err(ret);
|
||||
}
|
||||
#endif
|
||||
return (ret);
|
||||
}
|
||||
160
os/os_open.c
Normal file
160
os/os_open.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_open.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_open --
|
||||
* Open a file descriptor (including page size and log size information).
|
||||
*
|
||||
* PUBLIC: int __os_open __P((ENV *,
|
||||
* PUBLIC: const char *, u_int32_t, u_int32_t, int, DB_FH **));
|
||||
*/
|
||||
int
|
||||
__os_open(env, name, page_size, flags, mode, fhpp)
|
||||
ENV *env;
|
||||
const char *name;
|
||||
u_int32_t page_size, flags;
|
||||
int mode;
|
||||
DB_FH **fhpp;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
DB_FH *fhp;
|
||||
int oflags, ret;
|
||||
|
||||
COMPQUIET(page_size, 0);
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
*fhpp = NULL;
|
||||
oflags = 0;
|
||||
|
||||
if (dbenv != NULL &&
|
||||
FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env, "fileops: open %s", name);
|
||||
|
||||
#define OKFLAGS \
|
||||
(DB_OSO_ABSMODE | DB_OSO_CREATE | DB_OSO_DIRECT | DB_OSO_DSYNC |\
|
||||
DB_OSO_EXCL | DB_OSO_RDONLY | DB_OSO_REGION | DB_OSO_SEQ | \
|
||||
DB_OSO_TEMP | DB_OSO_TRUNC)
|
||||
if ((ret = __db_fchk(env, "__os_open", flags, OKFLAGS)) != 0)
|
||||
return (ret);
|
||||
|
||||
#if defined(O_BINARY)
|
||||
/*
|
||||
* If there's a binary-mode open flag, set it, we never want any
|
||||
* kind of translation. Some systems do translations by default,
|
||||
* e.g., with Cygwin, the default mode for an open() is set by the
|
||||
* mode of the mount that underlies the file.
|
||||
*/
|
||||
oflags |= O_BINARY;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DB requires the POSIX 1003.1 semantic that two files opened at the
|
||||
* same time with DB_OSO_CREATE/O_CREAT and DB_OSO_EXCL/O_EXCL flags
|
||||
* set return an EEXIST failure in at least one.
|
||||
*/
|
||||
if (LF_ISSET(DB_OSO_CREATE))
|
||||
oflags |= O_CREAT;
|
||||
|
||||
if (LF_ISSET(DB_OSO_EXCL))
|
||||
oflags |= O_EXCL;
|
||||
|
||||
#ifdef HAVE_O_DIRECT
|
||||
if (LF_ISSET(DB_OSO_DIRECT))
|
||||
oflags |= O_DIRECT;
|
||||
#endif
|
||||
#ifdef O_DSYNC
|
||||
if (LF_ISSET(DB_OSO_DSYNC))
|
||||
oflags |= O_DSYNC;
|
||||
#endif
|
||||
|
||||
if (LF_ISSET(DB_OSO_RDONLY))
|
||||
oflags |= O_RDONLY;
|
||||
else
|
||||
oflags |= O_RDWR;
|
||||
|
||||
if (LF_ISSET(DB_OSO_TRUNC))
|
||||
oflags |= O_TRUNC;
|
||||
|
||||
/*
|
||||
* Undocumented feature: allow applications to create intermediate
|
||||
* directories whenever a file is opened.
|
||||
*/
|
||||
if (dbenv != NULL &&
|
||||
env->dir_mode != 0 && LF_ISSET(DB_OSO_CREATE) &&
|
||||
(ret = __db_mkpath(env, name)) != 0)
|
||||
return (ret);
|
||||
|
||||
/* Open the file. */
|
||||
#ifdef HAVE_QNX
|
||||
if (LF_ISSET(DB_OSO_REGION))
|
||||
ret = __os_qnx_region_open(env, name, oflags, mode, &fhp);
|
||||
else
|
||||
#endif
|
||||
ret = __os_openhandle(env, name, oflags, mode, &fhp);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
if (LF_ISSET(DB_OSO_REGION))
|
||||
F_SET(fhp, DB_FH_REGION);
|
||||
#ifdef HAVE_FCHMOD
|
||||
/*
|
||||
* If the code using Berkeley DB is a library, that code may not be able
|
||||
* to control the application's umask value. Allow applications to set
|
||||
* absolute file modes. We can't fix the race between file creation and
|
||||
* the fchmod call -- we can't modify the process' umask here since the
|
||||
* process may be multi-threaded and the umask value is per-process, not
|
||||
* per-thread.
|
||||
*/
|
||||
if (LF_ISSET(DB_OSO_CREATE) && LF_ISSET(DB_OSO_ABSMODE))
|
||||
(void)fchmod(fhp->fd, mode);
|
||||
#endif
|
||||
|
||||
#ifdef O_DSYNC
|
||||
/*
|
||||
* If we can configure the file descriptor to flush on write, the
|
||||
* file descriptor does not need to be explicitly sync'd.
|
||||
*/
|
||||
if (LF_ISSET(DB_OSO_DSYNC))
|
||||
F_SET(fhp, DB_FH_NOSYNC);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DIRECTIO) && defined(DIRECTIO_ON)
|
||||
/*
|
||||
* The Solaris C library includes directio, but you have to set special
|
||||
* compile flags to #define DIRECTIO_ON. Require both in order to call
|
||||
* directio.
|
||||
*/
|
||||
if (LF_ISSET(DB_OSO_DIRECT))
|
||||
(void)directio(fhp->fd, DIRECTIO_ON);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Delete any temporary file.
|
||||
*
|
||||
* !!!
|
||||
* There's a race here, where we've created a file and we crash before
|
||||
* we can unlink it. Temporary files aren't common in DB, regardless,
|
||||
* it's not a security problem because the file is empty. There's no
|
||||
* reasonable way to avoid the race (playing signal games isn't worth
|
||||
* the portability nightmare), so we just live with it.
|
||||
*/
|
||||
if (LF_ISSET(DB_OSO_TEMP)) {
|
||||
#if defined(HAVE_UNLINK_WITH_OPEN_FAILURE) || defined(CONFIG_TEST)
|
||||
F_SET(fhp, DB_FH_UNLINK);
|
||||
#else
|
||||
(void)__os_unlink(env, name, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
*fhpp = fhp;
|
||||
return (0);
|
||||
}
|
||||
63
os/os_pid.c
Normal file
63
os/os_pid.c
Normal file
@@ -0,0 +1,63 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2001,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_pid.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
#ifdef HAVE_MUTEX_SUPPORT
|
||||
#include "dbinc/mutex_int.h" /* Required to load appropriate
|
||||
header files for thread functions. */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __os_id --
|
||||
* Return the current process ID.
|
||||
*
|
||||
* PUBLIC: void __os_id __P((DB_ENV *, pid_t *, db_threadid_t*));
|
||||
*/
|
||||
void
|
||||
__os_id(dbenv, pidp, tidp)
|
||||
DB_ENV *dbenv;
|
||||
pid_t *pidp;
|
||||
db_threadid_t *tidp;
|
||||
{
|
||||
/*
|
||||
* We can't depend on dbenv not being NULL, this routine is called
|
||||
* from places where there's no DB_ENV handle.
|
||||
*
|
||||
* We cache the pid in the ENV handle, getting the process ID is a
|
||||
* fairly slow call on lots of systems.
|
||||
*/
|
||||
if (pidp != NULL) {
|
||||
if (dbenv == NULL) {
|
||||
#if defined(HAVE_VXWORKS)
|
||||
*pidp = taskIdSelf();
|
||||
#else
|
||||
*pidp = getpid();
|
||||
#endif
|
||||
} else
|
||||
*pidp = dbenv->env->pid_cache;
|
||||
}
|
||||
|
||||
if (tidp != NULL) {
|
||||
#if defined(DB_WIN32)
|
||||
*tidp = GetCurrentThreadId();
|
||||
#elif defined(HAVE_MUTEX_UI_THREADS)
|
||||
*tidp = thr_self();
|
||||
#elif defined(HAVE_MUTEX_SOLARIS_LWP) || \
|
||||
defined(HAVE_MUTEX_PTHREADS) || defined(HAVE_PTHREAD_API)
|
||||
*tidp = pthread_self();
|
||||
#else
|
||||
/*
|
||||
* Default to just getpid.
|
||||
*/
|
||||
*tidp = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
52
os/os_rename.c
Normal file
52
os/os_rename.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_rename.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_rename --
|
||||
* Rename a file.
|
||||
*
|
||||
* PUBLIC: int __os_rename __P((ENV *,
|
||||
* PUBLIC: const char *, const char *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__os_rename(env, oldname, newname, silent)
|
||||
ENV *env;
|
||||
const char *oldname, *newname;
|
||||
u_int32_t silent;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int ret;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
if (dbenv != NULL &&
|
||||
FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env, "fileops: rename %s to %s", oldname, newname);
|
||||
|
||||
LAST_PANIC_CHECK_BEFORE_IO(env);
|
||||
|
||||
if (DB_GLOBAL(j_rename) != NULL)
|
||||
ret = DB_GLOBAL(j_rename)(oldname, newname);
|
||||
else
|
||||
RETRY_CHK((rename(oldname, newname)), ret);
|
||||
|
||||
/*
|
||||
* If "silent" is not set, then errors are OK and we should not output
|
||||
* an error message.
|
||||
*/
|
||||
if (ret != 0) {
|
||||
if (!silent)
|
||||
__db_syserr(
|
||||
env, ret, "rename %s %s", oldname, newname);
|
||||
ret = __os_posix_err(ret);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
27
os/os_root.c
Normal file
27
os/os_root.c
Normal file
@@ -0,0 +1,27 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1999,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_root.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_isroot --
|
||||
* Return if user has special permissions.
|
||||
*
|
||||
* PUBLIC: int __os_isroot __P((void));
|
||||
*/
|
||||
int
|
||||
__os_isroot()
|
||||
{
|
||||
#ifdef HAVE_GETUID
|
||||
return (getuid() == 0);
|
||||
#else
|
||||
return (0);
|
||||
#endif
|
||||
}
|
||||
36
os/os_rpath.c
Normal file
36
os/os_rpath.c
Normal file
@@ -0,0 +1,36 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_rpath.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __db_rpath --
|
||||
* Return the last path separator in the path or NULL if none found.
|
||||
*
|
||||
* PUBLIC: char *__db_rpath __P((const char *));
|
||||
*/
|
||||
char *
|
||||
__db_rpath(path)
|
||||
const char *path;
|
||||
{
|
||||
const char *s, *last;
|
||||
|
||||
s = path;
|
||||
last = NULL;
|
||||
if (PATH_SEPARATOR[1] != '\0') {
|
||||
for (; s[0] != '\0'; ++s)
|
||||
if (strchr(PATH_SEPARATOR, s[0]) != NULL)
|
||||
last = s;
|
||||
} else
|
||||
for (; s[0] != '\0'; ++s)
|
||||
if (s[0] == PATH_SEPARATOR[0])
|
||||
last = s;
|
||||
return ((char *)last);
|
||||
}
|
||||
285
os/os_rw.c
Normal file
285
os/os_rw.c
Normal file
@@ -0,0 +1,285 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_rw.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_io --
|
||||
* Do an I/O.
|
||||
*
|
||||
* PUBLIC: int __os_io __P((ENV *, int, DB_FH *, db_pgno_t,
|
||||
* PUBLIC: u_int32_t, u_int32_t, u_int32_t, u_int8_t *, size_t *));
|
||||
*/
|
||||
int
|
||||
__os_io(env, op, fhp, pgno, pgsize, relative, io_len, buf, niop)
|
||||
ENV *env;
|
||||
int op;
|
||||
DB_FH *fhp;
|
||||
db_pgno_t pgno;
|
||||
u_int32_t pgsize, relative, io_len;
|
||||
u_int8_t *buf;
|
||||
size_t *niop;
|
||||
{
|
||||
#if defined(HAVE_PREAD) && defined(HAVE_PWRITE)
|
||||
DB_ENV *dbenv;
|
||||
off_t offset;
|
||||
ssize_t nio;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Check for illegal usage.
|
||||
*
|
||||
* This routine is used in one of two ways: reading bytes from an
|
||||
* absolute offset and reading a specific database page. All of
|
||||
* our absolute offsets are known to fit into a u_int32_t, while
|
||||
* our database pages might be at offsets larger than a u_int32_t.
|
||||
* We don't want to specify an absolute offset in our caller as we
|
||||
* aren't exactly sure what size an off_t might be.
|
||||
*/
|
||||
DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
|
||||
DB_ASSERT(env, (pgno == 0 && pgsize == 0) || relative == 0);
|
||||
|
||||
#if defined(HAVE_PREAD) && defined(HAVE_PWRITE)
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
|
||||
if ((offset = relative) == 0)
|
||||
offset = (off_t)pgno * pgsize;
|
||||
switch (op) {
|
||||
case DB_IO_READ:
|
||||
if (DB_GLOBAL(j_read) != NULL)
|
||||
goto slow;
|
||||
#if defined(HAVE_STATISTICS)
|
||||
++fhp->read_count;
|
||||
#endif
|
||||
if (dbenv != NULL &&
|
||||
FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env,
|
||||
"fileops: read %s: %lu bytes at offset %lu",
|
||||
fhp->name, (u_long)io_len, (u_long)offset);
|
||||
|
||||
LAST_PANIC_CHECK_BEFORE_IO(env);
|
||||
nio = DB_GLOBAL(j_pread) != NULL ?
|
||||
DB_GLOBAL(j_pread)(fhp->fd, buf, io_len, offset) :
|
||||
pread(fhp->fd, buf, io_len, offset);
|
||||
break;
|
||||
case DB_IO_WRITE:
|
||||
if (DB_GLOBAL(j_write) != NULL)
|
||||
goto slow;
|
||||
#ifdef HAVE_FILESYSTEM_NOTZERO
|
||||
if (__os_fs_notzero())
|
||||
goto slow;
|
||||
#endif
|
||||
#if defined(HAVE_STATISTICS)
|
||||
++fhp->write_count;
|
||||
#endif
|
||||
if (dbenv != NULL &&
|
||||
FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env,
|
||||
"fileops: write %s: %lu bytes at offset %lu",
|
||||
fhp->name, (u_long)io_len, (u_long)offset);
|
||||
|
||||
LAST_PANIC_CHECK_BEFORE_IO(env);
|
||||
nio = DB_GLOBAL(j_pwrite) != NULL ?
|
||||
DB_GLOBAL(j_pwrite)(fhp->fd, buf, io_len, offset) :
|
||||
pwrite(fhp->fd, buf, io_len, offset);
|
||||
break;
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
if (nio == (ssize_t)io_len) {
|
||||
*niop = io_len;
|
||||
return (0);
|
||||
}
|
||||
slow:
|
||||
#endif
|
||||
MUTEX_LOCK(env, fhp->mtx_fh);
|
||||
|
||||
if ((ret = __os_seek(env, fhp, pgno, pgsize, relative)) != 0)
|
||||
goto err;
|
||||
switch (op) {
|
||||
case DB_IO_READ:
|
||||
ret = __os_read(env, fhp, buf, io_len, niop);
|
||||
break;
|
||||
case DB_IO_WRITE:
|
||||
ret = __os_write(env, fhp, buf, io_len, niop);
|
||||
break;
|
||||
default:
|
||||
ret = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
err: MUTEX_UNLOCK(env, fhp->mtx_fh);
|
||||
|
||||
return (ret);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_read --
|
||||
* Read from a file handle.
|
||||
*
|
||||
* PUBLIC: int __os_read __P((ENV *, DB_FH *, void *, size_t, size_t *));
|
||||
*/
|
||||
int
|
||||
__os_read(env, fhp, addr, len, nrp)
|
||||
ENV *env;
|
||||
DB_FH *fhp;
|
||||
void *addr;
|
||||
size_t len;
|
||||
size_t *nrp;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
size_t offset;
|
||||
ssize_t nr;
|
||||
int ret;
|
||||
u_int8_t *taddr;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
ret = 0;
|
||||
|
||||
DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
|
||||
|
||||
#if defined(HAVE_STATISTICS)
|
||||
++fhp->read_count;
|
||||
#endif
|
||||
if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env,
|
||||
"fileops: read %s: %lu bytes", fhp->name, (u_long)len);
|
||||
|
||||
if (DB_GLOBAL(j_read) != NULL) {
|
||||
*nrp = len;
|
||||
LAST_PANIC_CHECK_BEFORE_IO(env);
|
||||
if (DB_GLOBAL(j_read)(fhp->fd, addr, len) != (ssize_t)len) {
|
||||
ret = __os_get_syserr();
|
||||
__db_syserr(env, ret, "read: %#lx, %lu",
|
||||
P_TO_ULONG(addr), (u_long)len);
|
||||
ret = __os_posix_err(ret);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
for (taddr = addr, offset = 0;
|
||||
offset < len; taddr += nr, offset += (u_int32_t)nr) {
|
||||
LAST_PANIC_CHECK_BEFORE_IO(env);
|
||||
RETRY_CHK(((nr = read(fhp->fd,
|
||||
CHAR_STAR_CAST taddr, len - offset)) < 0 ? 1 : 0), ret);
|
||||
if (nr == 0 || ret != 0)
|
||||
break;
|
||||
}
|
||||
*nrp = (size_t)(taddr - (u_int8_t *)addr);
|
||||
if (ret != 0) {
|
||||
__db_syserr(env, ret, "read: %#lx, %lu",
|
||||
P_TO_ULONG(taddr), (u_long)len - offset);
|
||||
ret = __os_posix_err(ret);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_write --
|
||||
* Write to a file handle.
|
||||
*
|
||||
* PUBLIC: int __os_write __P((ENV *, DB_FH *, void *, size_t, size_t *));
|
||||
*/
|
||||
int
|
||||
__os_write(env, fhp, addr, len, nwp)
|
||||
ENV *env;
|
||||
DB_FH *fhp;
|
||||
void *addr;
|
||||
size_t len;
|
||||
size_t *nwp;
|
||||
{
|
||||
DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
|
||||
|
||||
#ifdef HAVE_FILESYSTEM_NOTZERO
|
||||
/* Zero-fill as necessary. */
|
||||
if (__os_fs_notzero()) {
|
||||
int ret;
|
||||
if ((ret = __db_zero_fill(env, fhp)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
||||
return (__os_physwrite(env, fhp, addr, len, nwp));
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_physwrite --
|
||||
* Physical write to a file handle.
|
||||
*
|
||||
* PUBLIC: int __os_physwrite
|
||||
* PUBLIC: __P((ENV *, DB_FH *, void *, size_t, size_t *));
|
||||
*/
|
||||
int
|
||||
__os_physwrite(env, fhp, addr, len, nwp)
|
||||
ENV *env;
|
||||
DB_FH *fhp;
|
||||
void *addr;
|
||||
size_t len;
|
||||
size_t *nwp;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
size_t offset;
|
||||
ssize_t nw;
|
||||
int ret;
|
||||
u_int8_t *taddr;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
ret = 0;
|
||||
|
||||
#if defined(HAVE_STATISTICS)
|
||||
++fhp->write_count;
|
||||
#endif
|
||||
if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env,
|
||||
"fileops: write %s: %lu bytes", fhp->name, (u_long)len);
|
||||
|
||||
#if defined(HAVE_FILESYSTEM_NOTZERO) && defined(DIAGNOSTIC)
|
||||
if (__os_fs_notzero()) {
|
||||
struct stat sb;
|
||||
off_t cur_off;
|
||||
|
||||
DB_ASSERT(env, fstat(fhp->fd, &sb) != -1 &&
|
||||
(cur_off = lseek(fhp->fd, (off_t)0, SEEK_CUR)) != -1 &&
|
||||
cur_off <= sb.st_size);
|
||||
}
|
||||
#endif
|
||||
if (DB_GLOBAL(j_write) != NULL) {
|
||||
*nwp = len;
|
||||
LAST_PANIC_CHECK_BEFORE_IO(env);
|
||||
if (DB_GLOBAL(j_write)(fhp->fd, addr, len) != (ssize_t)len) {
|
||||
ret = __os_get_syserr();
|
||||
__db_syserr(env, ret, "write: %#lx, %lu",
|
||||
P_TO_ULONG(addr), (u_long)len);
|
||||
ret = __os_posix_err(ret);
|
||||
|
||||
DB_EVENT(env, DB_EVENT_WRITE_FAILED, NULL);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
for (taddr = addr, offset = 0;
|
||||
offset < len; taddr += nw, offset += (u_int32_t)nw) {
|
||||
LAST_PANIC_CHECK_BEFORE_IO(env);
|
||||
RETRY_CHK(((nw = write(fhp->fd,
|
||||
CHAR_STAR_CAST taddr, len - offset)) < 0 ? 1 : 0), ret);
|
||||
if (ret != 0)
|
||||
break;
|
||||
}
|
||||
*nwp = len;
|
||||
if (ret != 0) {
|
||||
__db_syserr(env, ret, "write: %#lx, %lu",
|
||||
P_TO_ULONG(taddr), (u_long)len - offset);
|
||||
ret = __os_posix_err(ret);
|
||||
|
||||
DB_EVENT(env, DB_EVENT_WRITE_FAILED, NULL);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
64
os/os_seek.c
Normal file
64
os/os_seek.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_seek.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_seek --
|
||||
* Seek to a page/byte offset in the file.
|
||||
*
|
||||
* PUBLIC: int __os_seek __P((ENV *,
|
||||
* PUBLIC: DB_FH *, db_pgno_t, u_int32_t, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__os_seek(env, fhp, pgno, pgsize, relative)
|
||||
ENV *env;
|
||||
DB_FH *fhp;
|
||||
db_pgno_t pgno;
|
||||
u_int32_t pgsize;
|
||||
u_int32_t relative;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
off_t offset;
|
||||
int ret;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
|
||||
DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
|
||||
|
||||
#if defined(HAVE_STATISTICS)
|
||||
++fhp->seek_count;
|
||||
#endif
|
||||
|
||||
offset = (off_t)pgsize * pgno + relative;
|
||||
|
||||
if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env,
|
||||
"fileops: seek %s to %lu", fhp->name, (u_long)offset);
|
||||
|
||||
if (DB_GLOBAL(j_seek) != NULL)
|
||||
ret = DB_GLOBAL(j_seek)(fhp->fd, offset, SEEK_SET);
|
||||
else
|
||||
RETRY_CHK((lseek(
|
||||
fhp->fd, offset, SEEK_SET) == -1 ? 1 : 0), ret);
|
||||
|
||||
if (ret == 0) {
|
||||
fhp->pgsize = pgsize;
|
||||
fhp->pgno = pgno;
|
||||
fhp->offset = relative;
|
||||
} else {
|
||||
__db_syserr(env, ret,
|
||||
"seek: %lu: (%lu * %lu) + %lu", (u_long)offset,
|
||||
(u_long)pgno, (u_long)pgsize, (u_long)relative);
|
||||
ret = __os_posix_err(ret);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
45
os/os_stack.c
Normal file
45
os/os_stack.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2001,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_stack.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
#if defined(HAVE_SYSTEM_INCLUDE_FILES) && defined(HAVE_BACKTRACE) && \
|
||||
defined(HAVE_BACKTRACE_SYMBOLS) && defined(HAVE_EXECINFO_H)
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __os_stack --
|
||||
* Output a stack trace to the message file handle.
|
||||
*
|
||||
* PUBLIC: void __os_stack __P((ENV *));
|
||||
*/
|
||||
void
|
||||
__os_stack(env)
|
||||
ENV *env;
|
||||
{
|
||||
#if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
|
||||
void *array[200];
|
||||
size_t i, size;
|
||||
char **strings;
|
||||
|
||||
/*
|
||||
* Solaris and the GNU C library support this interface. Solaris
|
||||
* has additional interfaces (printstack and walkcontext), I don't
|
||||
* know if they offer any additional value or not.
|
||||
*/
|
||||
size = backtrace(array, sizeof(array) / sizeof(array[0]));
|
||||
strings = backtrace_symbols(array, size);
|
||||
|
||||
for (i = 0; i < size; ++i)
|
||||
__db_errx(env, "%s", strings[i]);
|
||||
free(strings);
|
||||
#endif
|
||||
COMPQUIET(env, NULL);
|
||||
}
|
||||
107
os/os_stat.c
Normal file
107
os/os_stat.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_stat.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_exists --
|
||||
* Return if the file exists.
|
||||
*
|
||||
* PUBLIC: int __os_exists __P((ENV *, const char *, int *));
|
||||
*/
|
||||
int
|
||||
__os_exists(env, path, isdirp)
|
||||
ENV *env;
|
||||
const char *path;
|
||||
int *isdirp;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
struct stat sb;
|
||||
int ret;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
|
||||
if (dbenv != NULL &&
|
||||
FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env, "fileops: stat %s", path);
|
||||
|
||||
if (DB_GLOBAL(j_exists) != NULL)
|
||||
return (DB_GLOBAL(j_exists)(path, isdirp));
|
||||
|
||||
RETRY_CHK((stat(CHAR_STAR_CAST path, &sb)), ret);
|
||||
if (ret != 0)
|
||||
return (__os_posix_err(ret));
|
||||
|
||||
#if !defined(S_ISDIR) || defined(STAT_MACROS_BROKEN)
|
||||
#undef S_ISDIR
|
||||
#ifdef _S_IFDIR
|
||||
#define S_ISDIR(m) (_S_IFDIR & (m))
|
||||
#else
|
||||
#define S_ISDIR(m) (((m) & 0170000) == 0040000)
|
||||
#endif
|
||||
#endif
|
||||
if (isdirp != NULL)
|
||||
*isdirp = S_ISDIR(sb.st_mode);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_ioinfo --
|
||||
* Return file size and I/O size; abstracted to make it easier
|
||||
* to replace.
|
||||
*
|
||||
* PUBLIC: int __os_ioinfo __P((ENV *, const char *,
|
||||
* PUBLIC: DB_FH *, u_int32_t *, u_int32_t *, u_int32_t *));
|
||||
*/
|
||||
int
|
||||
__os_ioinfo(env, path, fhp, mbytesp, bytesp, iosizep)
|
||||
ENV *env;
|
||||
const char *path;
|
||||
DB_FH *fhp;
|
||||
u_int32_t *mbytesp, *bytesp, *iosizep;
|
||||
{
|
||||
struct stat sb;
|
||||
int ret;
|
||||
|
||||
if (DB_GLOBAL(j_ioinfo) != NULL)
|
||||
return (DB_GLOBAL(j_ioinfo)(path,
|
||||
fhp->fd, mbytesp, bytesp, iosizep));
|
||||
|
||||
DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
|
||||
|
||||
RETRY_CHK((fstat(fhp->fd, &sb)), ret);
|
||||
if (ret != 0) {
|
||||
__db_syserr(env, ret, "fstat");
|
||||
return (__os_posix_err(ret));
|
||||
}
|
||||
|
||||
/* Return the size of the file. */
|
||||
if (mbytesp != NULL)
|
||||
*mbytesp = (u_int32_t)(sb.st_size / MEGABYTE);
|
||||
if (bytesp != NULL)
|
||||
*bytesp = (u_int32_t)(sb.st_size % MEGABYTE);
|
||||
|
||||
/*
|
||||
* Return the underlying filesystem I/O size, if available.
|
||||
*
|
||||
* XXX
|
||||
* Check for a 0 size -- the HP MPE/iX architecture has st_blksize,
|
||||
* but it's always 0.
|
||||
*/
|
||||
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
|
||||
if (iosizep != NULL && (*iosizep = sb.st_blksize) == 0)
|
||||
*iosizep = DB_DEF_IOSIZE;
|
||||
#else
|
||||
if (iosizep != NULL)
|
||||
*iosizep = DB_DEF_IOSIZE;
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
138
os/os_tmpdir.c
Normal file
138
os/os_tmpdir.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1998,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_tmpdir.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
#ifdef HAVE_SYSTEM_INCLUDE_FILES
|
||||
#ifdef macintosh
|
||||
#include <TFileSpec.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __os_tmpdir --
|
||||
* Set the temporary directory path.
|
||||
*
|
||||
* The order of items in the list structure and the order of checks in
|
||||
* the environment are documented.
|
||||
*
|
||||
* PUBLIC: int __os_tmpdir __P((ENV *, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__os_tmpdir(env, flags)
|
||||
ENV *env;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int isdir, ret;
|
||||
char *tdir, tdir_buf[DB_MAXPATHLEN];
|
||||
|
||||
dbenv = env->dbenv;
|
||||
|
||||
/* Use the environment if it's permitted and initialized. */
|
||||
if (LF_ISSET(DB_USE_ENVIRON) ||
|
||||
(LF_ISSET(DB_USE_ENVIRON_ROOT) && __os_isroot())) {
|
||||
/* POSIX: TMPDIR */
|
||||
tdir = tdir_buf;
|
||||
if ((ret = __os_getenv(
|
||||
env, "TMPDIR", &tdir, sizeof(tdir_buf))) != 0)
|
||||
return (ret);
|
||||
if (tdir != NULL && tdir[0] != '\0')
|
||||
goto found;
|
||||
|
||||
/*
|
||||
* Windows: TEMP, TMP
|
||||
*/
|
||||
tdir = tdir_buf;
|
||||
if ((ret = __os_getenv(
|
||||
env, "TEMP", &tdir, sizeof(tdir_buf))) != 0)
|
||||
return (ret);
|
||||
if (tdir != NULL && tdir[0] != '\0')
|
||||
goto found;
|
||||
|
||||
tdir = tdir_buf;
|
||||
if ((ret = __os_getenv(
|
||||
env, "TMP", &tdir, sizeof(tdir_buf))) != 0)
|
||||
return (ret);
|
||||
if (tdir != NULL && tdir[0] != '\0')
|
||||
goto found;
|
||||
|
||||
/* Macintosh */
|
||||
tdir = tdir_buf;
|
||||
if ((ret = __os_getenv(
|
||||
env, "TempFolder", &tdir, sizeof(tdir_buf))) != 0)
|
||||
return (ret);
|
||||
|
||||
if (tdir != NULL && tdir[0] != '\0')
|
||||
found: return (__os_strdup(env, tdir, &dbenv->db_tmp_dir));
|
||||
}
|
||||
|
||||
#ifdef macintosh
|
||||
/* Get the path to the temporary folder. */
|
||||
{FSSpec spec;
|
||||
|
||||
if (!Special2FSSpec(kTemporaryFolderType,
|
||||
kOnSystemDisk, 0, &spec))
|
||||
return (__os_strdup(env,
|
||||
FSp2FullPath(&spec), &dbenv->db_tmp_dir));
|
||||
}
|
||||
#endif
|
||||
#ifdef DB_WIN32
|
||||
/* Get the path to the temporary directory. */
|
||||
{
|
||||
_TCHAR tpath[DB_MAXPATHLEN + 1];
|
||||
char *path, *eos;
|
||||
|
||||
if (GetTempPath(DB_MAXPATHLEN, tpath) > 2) {
|
||||
FROM_TSTRING(env, tpath, path, ret);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
eos = path + strlen(path) - 1;
|
||||
if (*eos == '\\' || *eos == '/')
|
||||
*eos = '\0';
|
||||
if (__os_exists(env, path, &isdir) == 0 && isdir) {
|
||||
ret = __os_strdup(env,
|
||||
path, &dbenv->db_tmp_dir);
|
||||
FREE_STRING(env, path);
|
||||
return (ret);
|
||||
}
|
||||
FREE_STRING(env, path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Step through the static list looking for a possibility.
|
||||
*
|
||||
* We don't use the obvious data structure because some C compilers
|
||||
* (and I use the phrase loosely) don't like static data arrays.
|
||||
*/
|
||||
#define DB_TEMP_DIRECTORY(n) { \
|
||||
char *__p = n; \
|
||||
if (__os_exists(env, __p, &isdir) == 0 && isdir != 0) \
|
||||
return (__os_strdup(env, __p, &dbenv->db_tmp_dir)); \
|
||||
}
|
||||
#ifdef DB_WIN32
|
||||
DB_TEMP_DIRECTORY("/temp");
|
||||
DB_TEMP_DIRECTORY("C:/temp");
|
||||
DB_TEMP_DIRECTORY("C:/tmp");
|
||||
#else
|
||||
DB_TEMP_DIRECTORY("/var/tmp");
|
||||
DB_TEMP_DIRECTORY("/usr/tmp");
|
||||
DB_TEMP_DIRECTORY("/tmp");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If we don't have any other place to store temporary files, store
|
||||
* them in the current directory.
|
||||
*/
|
||||
return (__os_strdup(env, "", &dbenv->db_tmp_dir));
|
||||
}
|
||||
61
os/os_truncate.c
Normal file
61
os/os_truncate.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2004,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_truncate.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_truncate --
|
||||
* Truncate the file.
|
||||
*
|
||||
* PUBLIC: int __os_truncate __P((ENV *, DB_FH *, db_pgno_t, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__os_truncate(env, fhp, pgno, pgsize)
|
||||
ENV *env;
|
||||
DB_FH *fhp;
|
||||
db_pgno_t pgno;
|
||||
u_int32_t pgsize;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
off_t offset;
|
||||
int ret;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
|
||||
/*
|
||||
* Truncate a file so that "pgno" is discarded from the end of the
|
||||
* file.
|
||||
*/
|
||||
offset = (off_t)pgsize * pgno;
|
||||
|
||||
if (dbenv != NULL &&
|
||||
FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env,
|
||||
"fileops: truncate %s to %lu", fhp->name, (u_long)offset);
|
||||
|
||||
LAST_PANIC_CHECK_BEFORE_IO(env);
|
||||
|
||||
if (DB_GLOBAL(j_ftruncate) != NULL)
|
||||
ret = DB_GLOBAL(j_ftruncate)(fhp->fd, offset);
|
||||
else {
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
RETRY_CHK((ftruncate(fhp->fd, offset)), ret);
|
||||
#else
|
||||
ret = DB_OPNOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
__db_syserr(env, ret, "ftruncate: %lu", (u_long)offset);
|
||||
ret = __os_posix_err(ret);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
55
os/os_uid.c
Normal file
55
os/os_uid.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2001,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_uid.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_unique_id --
|
||||
* Return a unique 32-bit value.
|
||||
*
|
||||
* PUBLIC: void __os_unique_id __P((ENV *, u_int32_t *));
|
||||
*/
|
||||
void
|
||||
__os_unique_id(env, idp)
|
||||
ENV *env;
|
||||
u_int32_t *idp;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
db_timespec v;
|
||||
pid_t pid;
|
||||
u_int32_t id;
|
||||
|
||||
*idp = 0;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
|
||||
/*
|
||||
* Our randomized value is comprised of our process ID, the current
|
||||
* time of day and a stack address, all XOR'd together.
|
||||
*/
|
||||
__os_id(dbenv, &pid, NULL);
|
||||
__os_gettime(env, &v, 1);
|
||||
|
||||
id = (u_int32_t)pid ^
|
||||
(u_int32_t)v.tv_sec ^ (u_int32_t)v.tv_nsec ^ P_TO_UINT32(&pid);
|
||||
|
||||
/*
|
||||
* We could try and find a reasonable random-number generator, but
|
||||
* that's not all that easy to do. Seed and use srand()/rand(), if
|
||||
* we can find them.
|
||||
*/
|
||||
if (DB_GLOBAL(uid_init) == 0) {
|
||||
DB_GLOBAL(uid_init) = 1;
|
||||
srand((u_int)id);
|
||||
}
|
||||
id ^= (u_int)rand();
|
||||
|
||||
*idp = id;
|
||||
}
|
||||
78
os/os_unlink.c
Normal file
78
os/os_unlink.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_unlink.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* __os_unlink --
|
||||
* Remove a file.
|
||||
*
|
||||
* PUBLIC: int __os_unlink __P((ENV *, const char *, int));
|
||||
*/
|
||||
int
|
||||
__os_unlink(env, path, overwrite_test)
|
||||
ENV *env;
|
||||
const char *path;
|
||||
int overwrite_test;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
int ret, t_ret;
|
||||
|
||||
dbenv = env == NULL ? NULL : env->dbenv;
|
||||
|
||||
if (dbenv != NULL &&
|
||||
FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
|
||||
__db_msg(env, "fileops: unlink %s", path);
|
||||
|
||||
/* Optionally overwrite the contents of the file to enhance security. */
|
||||
if (dbenv != NULL && overwrite_test && F_ISSET(dbenv, DB_ENV_OVERWRITE))
|
||||
(void)__db_file_multi_write(env, path);
|
||||
|
||||
LAST_PANIC_CHECK_BEFORE_IO(env);
|
||||
|
||||
if (DB_GLOBAL(j_unlink) != NULL)
|
||||
ret = DB_GLOBAL(j_unlink)(path);
|
||||
else {
|
||||
RETRY_CHK((unlink(CHAR_STAR_CAST path)), ret);
|
||||
#ifdef HAVE_QNX
|
||||
/*
|
||||
* The file may be a region file created by shm_open, not a
|
||||
* regular file. Try and delete using unlink, and if that
|
||||
* fails for an unexpected reason, try a shared memory unlink.
|
||||
*/
|
||||
if (ret != 0 && __os_posix_err(ret) != ENOENT)
|
||||
RETRY_CHK((shm_unlink(path)), ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* !!!
|
||||
* The results of unlink are file system driver specific on VxWorks.
|
||||
* In the case of removing a file that did not exist, some, at least,
|
||||
* return an error, but with an errno of 0, not ENOENT. We do not
|
||||
* have to test for that explicitly, the RETRY_CHK macro resets "ret"
|
||||
* to be the errno, and so we'll just slide right on through.
|
||||
*
|
||||
* XXX
|
||||
* We shouldn't be testing for an errno of ENOENT here, but ENOENT
|
||||
* signals that a file is missing, and we attempt to unlink things
|
||||
* (such as v. 2.x environment regions, in ENV->remove) that we
|
||||
* are expecting not to be there. Reporting errors in these cases
|
||||
* is annoying.
|
||||
*/
|
||||
if (ret != 0) {
|
||||
t_ret = __os_posix_err(ret);
|
||||
if (t_ret != ENOENT)
|
||||
__db_syserr(env, ret, "unlink: %s", path);
|
||||
ret = t_ret;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
97
os/os_yield.c
Normal file
97
os/os_yield.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1997,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: os_yield.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#define __INCLUDE_SELECT_H 1
|
||||
#include "db_int.h"
|
||||
|
||||
#if defined(HAVE_SYSTEM_INCLUDE_FILES) && defined(HAVE_SCHED_YIELD)
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
static void __os_sleep __P((ENV *, u_long, u_long));
|
||||
|
||||
/*
|
||||
* __os_yield --
|
||||
* Yield the processor, optionally pausing until running again.
|
||||
*
|
||||
* PUBLIC: void __os_yield __P((ENV *, u_long, u_long));
|
||||
*/
|
||||
void
|
||||
__os_yield(env, secs, usecs)
|
||||
ENV *env;
|
||||
u_long secs, usecs; /* Seconds and microseconds. */
|
||||
{
|
||||
/*
|
||||
* Don't require the values be normalized (some operating systems
|
||||
* return an error if the usecs argument to select is too large).
|
||||
*/
|
||||
for (; usecs >= US_PER_SEC; usecs -= US_PER_SEC)
|
||||
++secs;
|
||||
|
||||
if (DB_GLOBAL(j_yield) != NULL) {
|
||||
(void)DB_GLOBAL(j_yield)(secs, usecs);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Yield the processor so other processes or threads can run. Use
|
||||
* the local yield call if not pausing, otherwise call the select
|
||||
* function.
|
||||
*/
|
||||
if (secs != 0 || usecs != 0)
|
||||
__os_sleep(env, secs, usecs);
|
||||
else {
|
||||
#if defined(HAVE_MUTEX_UI_THREADS)
|
||||
thr_yield();
|
||||
#elif defined(HAVE_PTHREAD_YIELD) && \
|
||||
(defined(HAVE_MUTEX_PTHREADS) || defined(HAVE_PTHREAD_API))
|
||||
pthread_yield();
|
||||
#elif defined(HAVE_SCHED_YIELD)
|
||||
(void)sched_yield();
|
||||
#elif defined(HAVE_YIELD)
|
||||
yield();
|
||||
#else
|
||||
__os_sleep(dbenv, 0, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* __os_sleep --
|
||||
* Pause the thread of control.
|
||||
*/
|
||||
static void
|
||||
__os_sleep(env, secs, usecs)
|
||||
ENV *env;
|
||||
u_long secs, usecs; /* Seconds and microseconds. */
|
||||
{
|
||||
struct timeval t;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Sheer raving paranoia -- don't select for 0 time, in case some
|
||||
* implementation doesn't yield the processor in that case.
|
||||
*/
|
||||
t.tv_sec = (long)secs;
|
||||
t.tv_usec = (long)usecs + 1;
|
||||
|
||||
/*
|
||||
* We don't catch interrupts and restart the system call here, unlike
|
||||
* other Berkeley DB system calls. This may be a user attempting to
|
||||
* interrupt a sleeping DB utility (for example, db_checkpoint), and
|
||||
* we want the utility to see the signal and quit. This assumes it's
|
||||
* always OK for DB to sleep for less time than originally scheduled.
|
||||
*/
|
||||
if (select(0, NULL, NULL, NULL, &t) == -1) {
|
||||
ret = __os_get_syserr();
|
||||
if (__os_posix_err(ret) != EINTR)
|
||||
__db_syserr(env, ret, "select");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user