mariadb/storage/bdb/mutex/mut_win32.c

298 lines
6.8 KiB
C
Raw Normal View History

2002-10-30 15:57:05 +04:00
/*
* See the file LICENSE for redistribution information.
*
2005-12-05 10:27:46 -08:00
* Copyright (c) 2002-2005
2002-10-30 15:57:05 +04:00
* Sleepycat Software. All rights reserved.
2005-07-20 15:48:22 -07:00
*
2005-12-05 10:27:46 -08:00
* $Id: mut_win32.c,v 12.15 2005/11/01 11:49:31 mjc Exp $
2002-10-30 15:57:05 +04:00
*/
#include "db_config.h"
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <string.h>
#endif
2005-12-05 10:27:46 -08:00
#include "db_int.h"
2002-10-30 15:57:05 +04:00
/*
* This is where we load in the actual test-and-set mutex code.
*/
#define LOAD_ACTUAL_MUTEX_CODE
2005-12-05 10:27:46 -08:00
#include "dbinc/mutex_int.h"
2002-10-30 15:57:05 +04:00
/* We don't want to run this code even in "ordinary" diagnostic mode. */
#undef MUTEX_DIAG
2005-12-05 10:27:46 -08:00
/*
* Common code to get an event handle. This is executed whenever a mutex
* blocks, or when unlocking a mutex that a thread is waiting on. We can't
* keep these handles around, since the mutex structure is in shared memory,
* and each process gets its own handle value.
*
* We pass security attributes so that the created event is accessible by all
* users, in case a Windows service is sharing an environment with a local
* process run as a different user.
*/
2005-07-20 15:48:22 -07:00
static _TCHAR hex_digits[] = _T("0123456789abcdef");
2005-12-05 10:27:46 -08:00
static SECURITY_DESCRIPTOR null_sd;
static SECURITY_ATTRIBUTES all_sa;
static int security_initialized = 0;
static __inline int get_handle(dbenv, mutexp, eventp)
DB_ENV *dbenv;
DB_MUTEX *mutexp;
HANDLE *eventp;
{
_TCHAR idbuf[] = _T("db.m00000000");
_TCHAR *p = idbuf + 12;
int ret = 0;
u_int32_t id;
for (id = (mutexp)->id; id != 0; id >>= 4)
*--p = hex_digits[id & 0xf];
if (!security_initialized) {
InitializeSecurityDescriptor(&null_sd,
SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&null_sd, TRUE, 0, FALSE);
all_sa.nLength = sizeof(SECURITY_ATTRIBUTES);
all_sa.bInheritHandle = FALSE;
all_sa.lpSecurityDescriptor = &null_sd;
security_initialized = 1;
}
2005-07-20 15:48:22 -07:00
2005-12-05 10:27:46 -08:00
if ((*eventp = CreateEvent(&all_sa, FALSE, FALSE, idbuf)) == NULL) {
ret = __os_get_errno();
__db_err(dbenv, "Win32 create event failed: %s",
db_strerror(ret));
}
return (ret);
}
2002-10-30 15:57:05 +04:00
/*
* __db_win32_mutex_init --
2005-12-05 10:27:46 -08:00
* Initialize a Win32 mutex.
2002-10-30 15:57:05 +04:00
*
2005-12-05 10:27:46 -08:00
* PUBLIC: int __db_win32_mutex_init __P((DB_ENV *, db_mutex_t, u_int32_t));
2002-10-30 15:57:05 +04:00
*/
int
2005-12-05 10:27:46 -08:00
__db_win32_mutex_init(dbenv, mutex, flags)
2002-10-30 15:57:05 +04:00
DB_ENV *dbenv;
2005-12-05 10:27:46 -08:00
db_mutex_t mutex;
2002-10-30 15:57:05 +04:00
u_int32_t flags;
{
2005-12-05 10:27:46 -08:00
DB_MUTEX *mutexp;
DB_MUTEXMGR *mtxmgr;
DB_MUTEXREGION *mtxregion;
2002-10-30 15:57:05 +04:00
2005-12-05 10:27:46 -08:00
mtxmgr = dbenv->mutex_handle;
mtxregion = mtxmgr->reginfo.primary;
mutexp = MUTEXP_SET(mutex);
2002-10-30 15:57:05 +04:00
2005-07-20 15:48:22 -07:00
mutexp->id = ((getpid() & 0xffff) << 16) ^ P_TO_UINT32(mutexp);
2005-12-05 10:27:46 -08:00
2002-10-30 15:57:05 +04:00
return (0);
}
/*
* __db_win32_mutex_lock
2005-12-05 10:27:46 -08:00
* Lock on a mutex, blocking if necessary.
2002-10-30 15:57:05 +04:00
*
2005-12-05 10:27:46 -08:00
* PUBLIC: int __db_win32_mutex_lock __P((DB_ENV *, db_mutex_t));
2002-10-30 15:57:05 +04:00
*/
int
2005-12-05 10:27:46 -08:00
__db_win32_mutex_lock(dbenv, mutex)
2002-10-30 15:57:05 +04:00
DB_ENV *dbenv;
2005-12-05 10:27:46 -08:00
db_mutex_t mutex;
2002-10-30 15:57:05 +04:00
{
2005-12-05 10:27:46 -08:00
DB_MUTEX *mutexp;
DB_MUTEXMGR *mtxmgr;
DB_MUTEXREGION *mtxregion;
2002-10-30 15:57:05 +04:00
HANDLE event;
2005-07-20 15:48:22 -07:00
u_int32_t nspins;
2005-12-05 10:27:46 -08:00
int ms, ret;
2002-10-30 15:57:05 +04:00
#ifdef MUTEX_DIAG
LARGE_INTEGER now;
#endif
2005-12-05 10:27:46 -08:00
if (!MUTEX_ON(dbenv) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
2002-10-30 15:57:05 +04:00
return (0);
2005-12-05 10:27:46 -08:00
mtxmgr = dbenv->mutex_handle;
mtxregion = mtxmgr->reginfo.primary;
mutexp = MUTEXP_SET(mutex);
2002-10-30 15:57:05 +04:00
event = NULL;
ms = 50;
ret = 0;
loop: /* Attempt to acquire the resource for N spins. */
2005-12-05 10:27:46 -08:00
for (nspins =
mtxregion->stat.st_mutex_tas_spins; nspins > 0; --nspins) {
/*
* We can avoid the (expensive) interlocked instructions if
* the mutex is already "set".
*/
if (mutexp->tas || !MUTEX_SET(&mutexp->tas)) {
2005-07-20 15:48:22 -07:00
/*
* Some systems (notably those with newer Intel CPUs)
* need a small pause here. [#6975]
*/
#ifdef MUTEX_PAUSE
MUTEX_PAUSE
#endif
2002-10-30 15:57:05 +04:00
continue;
2005-07-20 15:48:22 -07:00
}
2002-10-30 15:57:05 +04:00
#ifdef DIAGNOSTIC
2005-12-05 10:27:46 -08:00
if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
char buf[DB_THREADID_STRLEN];
2002-10-30 15:57:05 +04:00
__db_err(dbenv,
2005-12-05 10:27:46 -08:00
"Win32 lock failed: mutex already locked by %s",
dbenv->thread_id_string(dbenv,
mutexp->pid, mutexp->tid, buf));
return (__db_panic(dbenv, EACCES));
}
2002-10-30 15:57:05 +04:00
#endif
2005-12-05 10:27:46 -08:00
F_SET(mutexp, DB_MUTEX_LOCKED);
dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid);
CHECK_MTX_THREAD(dbenv, mutexp);
2002-10-30 15:57:05 +04:00
2005-12-05 10:27:46 -08:00
#ifdef HAVE_STATISTICS
2002-10-30 15:57:05 +04:00
if (event == NULL)
++mutexp->mutex_set_nowait;
2005-12-05 10:27:46 -08:00
else
2002-10-30 15:57:05 +04:00
++mutexp->mutex_set_wait;
2005-12-05 10:27:46 -08:00
#endif
if (event != NULL) {
2005-07-20 15:48:22 -07:00
CloseHandle(event);
2002-10-30 15:57:05 +04:00
InterlockedDecrement(&mutexp->nwaiters);
#ifdef MUTEX_DIAG
if (ret != WAIT_OBJECT_0) {
QueryPerformanceCounter(&now);
printf("[%I64d]: Lost signal on mutex %p, "
"id %d, ms %d\n",
now.QuadPart, mutexp, mutexp->id, ms);
}
#endif
}
2005-12-05 10:27:46 -08:00
#ifdef DIAGNOSTIC
/*
* We want to switch threads as often as possible. Yield
* every time we get a mutex to ensure contention.
*/
if (F_ISSET(dbenv, DB_ENV_YIELDCPU))
__os_yield(NULL, 1);
#endif
2002-10-30 15:57:05 +04:00
return (0);
}
/*
* Yield the processor; wait 50 ms initially, up to 1 second. This
* loop is needed to work around a race where the signal from the
* unlocking thread gets lost. We start at 50 ms because it's unlikely
* to happen often and we want to avoid wasting CPU.
*/
if (event == NULL) {
#ifdef MUTEX_DIAG
QueryPerformanceCounter(&now);
printf("[%I64d]: Waiting on mutex %p, id %d\n",
now.QuadPart, mutexp, mutexp->id);
#endif
InterlockedIncrement(&mutexp->nwaiters);
2005-12-05 10:27:46 -08:00
if ((ret = get_handle(dbenv, mutexp, &event)) != 0)
goto err;
}
if ((ret = WaitForSingleObject(event, ms)) == WAIT_FAILED) {
ret = __os_get_errno();
goto err;
2002-10-30 15:57:05 +04:00
}
if ((ms <<= 1) > MS_PER_SEC)
ms = MS_PER_SEC;
2005-12-05 10:27:46 -08:00
PANIC_CHECK(dbenv);
2002-10-30 15:57:05 +04:00
goto loop;
2005-12-05 10:27:46 -08:00
err: __db_err(dbenv, "Win32 lock failed: %s", db_strerror(ret));
return (__db_panic(dbenv, ret));
2002-10-30 15:57:05 +04:00
}
/*
* __db_win32_mutex_unlock --
2005-12-05 10:27:46 -08:00
* Release a mutex.
2002-10-30 15:57:05 +04:00
*
2005-12-05 10:27:46 -08:00
* PUBLIC: int __db_win32_mutex_unlock __P((DB_ENV *, db_mutex_t));
2002-10-30 15:57:05 +04:00
*/
int
2005-12-05 10:27:46 -08:00
__db_win32_mutex_unlock(dbenv, mutex)
2002-10-30 15:57:05 +04:00
DB_ENV *dbenv;
2005-12-05 10:27:46 -08:00
db_mutex_t mutex;
2002-10-30 15:57:05 +04:00
{
2005-12-05 10:27:46 -08:00
DB_MUTEX *mutexp;
DB_MUTEXMGR *mtxmgr;
DB_MUTEXREGION *mtxregion;
2002-10-30 15:57:05 +04:00
HANDLE event;
2005-12-05 10:27:46 -08:00
int ret;
2002-10-30 15:57:05 +04:00
#ifdef MUTEX_DIAG
2005-12-05 10:27:46 -08:00
LARGE_INTEGER now;
2002-10-30 15:57:05 +04:00
#endif
2005-12-05 10:27:46 -08:00
if (!MUTEX_ON(dbenv) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
2002-10-30 15:57:05 +04:00
return (0);
2005-12-05 10:27:46 -08:00
mtxmgr = dbenv->mutex_handle;
mtxregion = mtxmgr->reginfo.primary;
mutexp = MUTEXP_SET(mutex);
2002-10-30 15:57:05 +04:00
2005-12-05 10:27:46 -08:00
#ifdef DIAGNOSTIC
if (!mutexp->tas || !F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
__db_err(dbenv, "Win32 unlock failed: lock already unlocked");
return (__db_panic(dbenv, EACCES));
}
2002-10-30 15:57:05 +04:00
#endif
2005-12-05 10:27:46 -08:00
F_CLR(mutexp, DB_MUTEX_LOCKED);
2002-10-30 15:57:05 +04:00
MUTEX_UNSET(&mutexp->tas);
if (mutexp->nwaiters > 0) {
2005-12-05 10:27:46 -08:00
if ((ret = get_handle(dbenv, mutexp, &event)) != 0)
goto err;
2002-10-30 15:57:05 +04:00
#ifdef MUTEX_DIAG
QueryPerformanceCounter(&now);
printf("[%I64d]: Signalling mutex %p, id %d\n",
now.QuadPart, mutexp, mutexp->id);
#endif
2005-12-05 10:27:46 -08:00
if (!PulseEvent(event)) {
2005-07-20 15:48:22 -07:00
ret = __os_get_errno();
2005-12-05 10:27:46 -08:00
CloseHandle(event);
goto err;
}
2002-10-30 15:57:05 +04:00
2005-07-20 15:48:22 -07:00
CloseHandle(event);
2002-10-30 15:57:05 +04:00
}
2005-12-05 10:27:46 -08:00
return (0);
2002-10-30 15:57:05 +04:00
2005-12-05 10:27:46 -08:00
err: __db_err(dbenv, "Win32 unlock failed: %s", db_strerror(ret));
return (__db_panic(dbenv, ret));
2002-10-30 15:57:05 +04:00
}
/*
* __db_win32_mutex_destroy --
2005-12-05 10:27:46 -08:00
* Destroy a mutex.
2002-10-30 15:57:05 +04:00
*
2005-12-05 10:27:46 -08:00
* PUBLIC: int __db_win32_mutex_destroy __P((DB_ENV *, db_mutex_t));
2002-10-30 15:57:05 +04:00
*/
int
2005-12-05 10:27:46 -08:00
__db_win32_mutex_destroy(dbenv, mutex)
DB_ENV *dbenv;
db_mutex_t mutex;
2002-10-30 15:57:05 +04:00
{
2005-07-20 15:48:22 -07:00
return (0);
2002-10-30 15:57:05 +04:00
}