Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

mut_win32.c

00001 /*
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2002-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: mut_win32.c,v 12.15 2005/11/01 11:49:31 mjc Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #endif
00017 
00018 #include "db_int.h"
00019 
00020 /*
00021  * This is where we load in the actual test-and-set mutex code.
00022  */
00023 #define LOAD_ACTUAL_MUTEX_CODE
00024 #include "dbinc/mutex_int.h"
00025 
00026 /* We don't want to run this code even in "ordinary" diagnostic mode. */
00027 #undef MUTEX_DIAG
00028 
00029 /*
00030  * Common code to get an event handle.  This is executed whenever a mutex
00031  * blocks, or when unlocking a mutex that a thread is waiting on.  We can't
00032  * keep these handles around, since the mutex structure is in shared memory,
00033  * and each process gets its own handle value.
00034  *
00035  * We pass security attributes so that the created event is accessible by all
00036  * users, in case a Windows service is sharing an environment with a local
00037  * process run as a different user.
00038  */
00039 static _TCHAR hex_digits[] = _T("0123456789abcdef");
00040 static SECURITY_DESCRIPTOR null_sd;
00041 static SECURITY_ATTRIBUTES all_sa;
00042 static int security_initialized = 0;
00043 
00044 static __inline int get_handle(dbenv, mutexp, eventp)
00045         DB_ENV *dbenv;
00046         DB_MUTEX *mutexp;
00047         HANDLE *eventp;
00048 {
00049         _TCHAR idbuf[] = _T("db.m00000000");
00050         _TCHAR *p = idbuf + 12;
00051         int ret = 0;
00052         u_int32_t id;
00053 
00054         for (id = (mutexp)->id; id != 0; id >>= 4)
00055                 *--p = hex_digits[id & 0xf];
00056 
00057         if (!security_initialized) {
00058                 InitializeSecurityDescriptor(&null_sd,
00059                     SECURITY_DESCRIPTOR_REVISION);
00060                 SetSecurityDescriptorDacl(&null_sd, TRUE, 0, FALSE);
00061                 all_sa.nLength = sizeof(SECURITY_ATTRIBUTES);
00062                 all_sa.bInheritHandle = FALSE;
00063                 all_sa.lpSecurityDescriptor = &null_sd;
00064                 security_initialized = 1;
00065         }
00066 
00067         if ((*eventp = CreateEvent(&all_sa, FALSE, FALSE, idbuf)) == NULL) {
00068                 ret = __os_get_errno();
00069                 __db_err(dbenv, "Win32 create event failed: %s",
00070                     db_strerror(ret));
00071         }
00072 
00073         return (ret);
00074 }
00075 
00076 /*
00077  * __db_win32_mutex_init --
00078  *      Initialize a Win32 mutex.
00079  *
00080  * PUBLIC: int __db_win32_mutex_init __P((DB_ENV *, db_mutex_t, u_int32_t));
00081  */
00082 int
00083 __db_win32_mutex_init(dbenv, mutex, flags)
00084         DB_ENV *dbenv;
00085         db_mutex_t mutex;
00086         u_int32_t flags;
00087 {
00088         DB_MUTEX *mutexp;
00089         DB_MUTEXMGR *mtxmgr;
00090         DB_MUTEXREGION *mtxregion;
00091 
00092         mtxmgr = dbenv->mutex_handle;
00093         mtxregion = mtxmgr->reginfo.primary;
00094         mutexp = MUTEXP_SET(mutex);
00095 
00096         mutexp->id = ((getpid() & 0xffff) << 16) ^ P_TO_UINT32(mutexp);
00097 
00098         return (0);
00099 }
00100 
00101 /*
00102  * __db_win32_mutex_lock
00103  *      Lock on a mutex, blocking if necessary.
00104  *
00105  * PUBLIC: int __db_win32_mutex_lock __P((DB_ENV *, db_mutex_t));
00106  */
00107 int
00108 __db_win32_mutex_lock(dbenv, mutex)
00109         DB_ENV *dbenv;
00110         db_mutex_t mutex;
00111 {
00112         DB_MUTEX *mutexp;
00113         DB_MUTEXMGR *mtxmgr;
00114         DB_MUTEXREGION *mtxregion;
00115         HANDLE event;
00116         u_int32_t nspins;
00117         int ms, ret;
00118 #ifdef MUTEX_DIAG
00119         LARGE_INTEGER now;
00120 #endif
00121 
00122         if (!MUTEX_ON(dbenv) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
00123                 return (0);
00124 
00125         mtxmgr = dbenv->mutex_handle;
00126         mtxregion = mtxmgr->reginfo.primary;
00127         mutexp = MUTEXP_SET(mutex);
00128 
00129         event = NULL;
00130         ms = 50;
00131         ret = 0;
00132 
00133 loop:   /* Attempt to acquire the resource for N spins. */
00134         for (nspins =
00135             mtxregion->stat.st_mutex_tas_spins; nspins > 0; --nspins) {
00136                 /*
00137                  * We can avoid the (expensive) interlocked instructions if
00138                  * the mutex is already "set".
00139                  */
00140                 if (mutexp->tas || !MUTEX_SET(&mutexp->tas)) {
00141                         /*
00142                          * Some systems (notably those with newer Intel CPUs)
00143                          * need a small pause here. [#6975]
00144                          */
00145 #ifdef MUTEX_PAUSE
00146                         MUTEX_PAUSE
00147 #endif
00148                         continue;
00149                 }
00150 
00151 #ifdef DIAGNOSTIC
00152                 if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
00153                         char buf[DB_THREADID_STRLEN];
00154                         __db_err(dbenv,
00155                             "Win32 lock failed: mutex already locked by %s",
00156                              dbenv->thread_id_string(dbenv,
00157                              mutexp->pid, mutexp->tid, buf));
00158                         return (__db_panic(dbenv, EACCES));
00159                 }
00160 #endif
00161                 F_SET(mutexp, DB_MUTEX_LOCKED);
00162                 dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid);
00163                 CHECK_MTX_THREAD(dbenv, mutexp);
00164 
00165 #ifdef HAVE_STATISTICS
00166                 if (event == NULL)
00167                         ++mutexp->mutex_set_nowait;
00168                 else
00169                         ++mutexp->mutex_set_wait;
00170 #endif
00171                 if (event != NULL) {
00172                         CloseHandle(event);
00173                         InterlockedDecrement(&mutexp->nwaiters);
00174 #ifdef MUTEX_DIAG
00175                         if (ret != WAIT_OBJECT_0) {
00176                                 QueryPerformanceCounter(&now);
00177                                 printf("[%I64d]: Lost signal on mutex %p, "
00178                                     "id %d, ms %d\n",
00179                                     now.QuadPart, mutexp, mutexp->id, ms);
00180                         }
00181 #endif
00182                 }
00183 
00184 #ifdef DIAGNOSTIC
00185                 /*
00186                  * We want to switch threads as often as possible.  Yield
00187                  * every time we get a mutex to ensure contention.
00188                  */
00189                 if (F_ISSET(dbenv, DB_ENV_YIELDCPU))
00190                         __os_yield(NULL, 1);
00191 #endif
00192 
00193                 return (0);
00194         }
00195 
00196         /*
00197          * Yield the processor; wait 50 ms initially, up to 1 second.  This
00198          * loop is needed to work around a race where the signal from the
00199          * unlocking thread gets lost.  We start at 50 ms because it's unlikely
00200          * to happen often and we want to avoid wasting CPU.
00201          */
00202         if (event == NULL) {
00203 #ifdef MUTEX_DIAG
00204                 QueryPerformanceCounter(&now);
00205                 printf("[%I64d]: Waiting on mutex %p, id %d\n",
00206                     now.QuadPart, mutexp, mutexp->id);
00207 #endif
00208                 InterlockedIncrement(&mutexp->nwaiters);
00209                 if ((ret = get_handle(dbenv, mutexp, &event)) != 0)
00210                         goto err;
00211         }
00212         if ((ret = WaitForSingleObject(event, ms)) == WAIT_FAILED) {
00213                 ret = __os_get_errno();
00214                 goto err;
00215         }
00216         if ((ms <<= 1) > MS_PER_SEC)
00217                 ms = MS_PER_SEC;
00218 
00219         PANIC_CHECK(dbenv);
00220         goto loop;
00221 
00222 err:    __db_err(dbenv, "Win32 lock failed: %s", db_strerror(ret));
00223         return (__db_panic(dbenv, ret));
00224 }
00225 
00226 /*
00227  * __db_win32_mutex_unlock --
00228  *      Release a mutex.
00229  *
00230  * PUBLIC: int __db_win32_mutex_unlock __P((DB_ENV *, db_mutex_t));
00231  */
00232 int
00233 __db_win32_mutex_unlock(dbenv, mutex)
00234         DB_ENV *dbenv;
00235         db_mutex_t mutex;
00236 {
00237         DB_MUTEX *mutexp;
00238         DB_MUTEXMGR *mtxmgr;
00239         DB_MUTEXREGION *mtxregion;
00240         HANDLE event;
00241         int ret;
00242 #ifdef MUTEX_DIAG
00243         LARGE_INTEGER now;
00244 #endif
00245         if (!MUTEX_ON(dbenv) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
00246                 return (0);
00247 
00248         mtxmgr = dbenv->mutex_handle;
00249         mtxregion = mtxmgr->reginfo.primary;
00250         mutexp = MUTEXP_SET(mutex);
00251 
00252 #ifdef DIAGNOSTIC
00253         if (!mutexp->tas || !F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
00254                 __db_err(dbenv, "Win32 unlock failed: lock already unlocked");
00255                 return (__db_panic(dbenv, EACCES));
00256         }
00257 #endif
00258         F_CLR(mutexp, DB_MUTEX_LOCKED);
00259         MUTEX_UNSET(&mutexp->tas);
00260 
00261         if (mutexp->nwaiters > 0) {
00262                 if ((ret = get_handle(dbenv, mutexp, &event)) != 0)
00263                         goto err;
00264 
00265 #ifdef MUTEX_DIAG
00266                 QueryPerformanceCounter(&now);
00267                 printf("[%I64d]: Signalling mutex %p, id %d\n",
00268                     now.QuadPart, mutexp, mutexp->id);
00269 #endif
00270                 if (!PulseEvent(event)) {
00271                         ret = __os_get_errno();
00272                         CloseHandle(event);
00273                         goto err;
00274                 }
00275 
00276                 CloseHandle(event);
00277         }
00278 
00279         return (0);
00280 
00281 err:    __db_err(dbenv, "Win32 unlock failed: %s", db_strerror(ret));
00282         return (__db_panic(dbenv, ret));
00283 }
00284 
00285 /*
00286  * __db_win32_mutex_destroy --
00287  *      Destroy a mutex.
00288  *
00289  * PUBLIC: int __db_win32_mutex_destroy __P((DB_ENV *, db_mutex_t));
00290  */
00291 int
00292 __db_win32_mutex_destroy(dbenv, mutex)
00293         DB_ENV *dbenv;
00294         db_mutex_t mutex;
00295 {
00296         return (0);
00297 }

Generated on Sun Dec 25 12:14:41 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2