mutex.h

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996, 1997, 1998, 1999, 2000
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: mutex_8h-source.html,v 1.1 2008/06/08 10:20:57 sebdiaz Exp $
00008  */
00009 
00010 #define DB_BEGIN_SINGLE_THREAD
00011 #define DB_END_SINGLE_THREAD
00012 
00013 /*********************************************************************
00014  * POSIX.1 pthreads interface.
00015  *********************************************************************/
00016 #ifdef HAVE_MUTEX_PTHREADS
00017 #include <pthread.h>
00018 
00019 #define MUTEX_FIELDS                                                    \
00020         pthread_mutex_t mutex;          /* Mutex. */                    \
00021         pthread_cond_t  cond;           /* Condition variable. */
00022 #endif
00023 
00024 /*********************************************************************
00025  * Solaris lwp threads interface.
00026  *
00027  * !!!
00028  * We use LWP mutexes on Solaris instead of UI or POSIX mutexes (both of
00029  * which are available), for two reasons.  First, the Solaris C library
00030  * includes versions of the both UI and POSIX thread mutex interfaces, but
00031  * they are broken in that they don't support inter-process locking, and
00032  * there's no way to detect it, e.g., calls to configure the mutexes for
00033  * inter-process locking succeed without error.  So, we use LWP mutexes so
00034  * that we don't fail in fairly undetectable ways because the application
00035  * wasn't linked with the appropriate threads library.  Second, there were
00036  * bugs in SunOS 5.7 (Solaris 7) where if an application loaded the C library
00037  * before loading the libthread/libpthread threads libraries (e.g., by using
00038  * dlopen to load the DB library), the pwrite64 interface would be translated
00039  * into a call to pwrite and DB would drop core.
00040  *********************************************************************/
00041 #ifdef HAVE_MUTEX_SOLARIS_LWP
00042 /*
00043  * XXX
00044  * Don't change <synch.h> to <sys/lwp.h> -- although lwp.h is listed in the
00045  * Solaris manual page as the correct include to use, it causes the Solaris
00046  * compiler on SunOS 2.6 to fail.
00047  */
00048 #include <synch.h>
00049 
00050 #define MUTEX_FIELDS                                                    \
00051         lwp_mutex_t mutex;              /* Mutex. */                    \
00052         lwp_cond_t cond;                /* Condition variable. */
00053 #endif
00054 
00055 /*********************************************************************
00056  * Solaris/Unixware threads interface.
00057  *********************************************************************/
00058 #ifdef HAVE_MUTEX_UI_THREADS
00059 #include <thread.h>
00060 #include <synch.h>
00061 
00062 #define MUTEX_FIELDS                                                    \
00063         mutex_t mutex;                  /* Mutex. */                    \
00064         cond_t  cond;                   /* Condition variable. */
00065 #endif
00066 
00067 /*********************************************************************
00068  * AIX C library functions.
00069  *********************************************************************/
00070 #ifdef HAVE_MUTEX_AIX_CHECK_LOCK
00071 #include <sys/atomic_op.h>
00072 typedef int tsl_t;
00073 
00074 #define MUTEX_INIT(x)   0
00075 #define MUTEX_ALIGN     sizeof(int)
00076 #define MUTEX_SET(x)    (!_check_lock(x, 0, 1))
00077 #define MUTEX_UNSET(x)  _clear_lock(x, 0)
00078 #endif
00079 
00080 /*********************************************************************
00081  * General C library functions (msemaphore).
00082  *
00083  * !!!
00084  * Check for HPPA as a special case, because it requires unusual alignment,
00085  * and doesn't support semaphores in malloc(3) or shmget(2) memory.
00086  *
00087  * !!!
00088  * Do not remove the MSEM_IF_NOWAIT flag.  The problem is that if a single
00089  * process makes two msem_lock() calls in a row, the second one returns an
00090  * error.  We depend on the fact that we can lock against ourselves in the
00091  * locking subsystem, where we set up a mutex so that we can block ourselves.
00092  * Tested on OSF1 v4.0.
00093  *********************************************************************/
00094 #ifdef HAVE_MUTEX_HPPA_MSEM_INIT
00095 #define MUTEX_NO_MALLOC_LOCKS
00096 #define MUTEX_NO_SHMGET_LOCKS
00097 
00098 #define MUTEX_ALIGN     16
00099 #endif
00100 
00101 #if defined(HAVE_MUTEX_MSEM_INIT) || defined(HAVE_MUTEX_HPPA_MSEM_INIT)
00102 #include <sys/mman.h>
00103 typedef msemaphore tsl_t;
00104 
00105 #ifndef MUTEX_ALIGN
00106 #define MUTEX_ALIGN     sizeof(int)
00107 #endif
00108 #define MUTEX_INIT(x)   (msem_init(x, MSEM_UNLOCKED) <= (msemaphore *)0)
00109 #define MUTEX_SET(x)    (!msem_lock(x, MSEM_IF_NOWAIT))
00110 #define MUTEX_UNSET(x)  msem_unlock(x, 0)
00111 #endif
00112 
00113 /*********************************************************************
00114  * MacOS.
00115  *
00116  * !!!
00117  * We should simplify this by always returning a no-need-to-lock lock
00118  * when we initialize the mutex.
00119  *********************************************************************/
00120 #ifdef HAVE_MUTEX_MACOS
00121 typedef unsigned char tsl_t;
00122 
00123 #define MUTEX_INIT(x)   0
00124 #endif
00125 
00126 /*********************************************************************
00127  * Reliant UNIX C library functions.
00128  *********************************************************************/
00129 #ifdef HAVE_MUTEX_RELIANTUNIX_INITSPIN
00130 #include <ulocks.h>
00131 typedef spinlock_t tsl_t;
00132 
00133 #define MUTEX_INIT(x)   (initspin(x, 1), 0)
00134 #define MUTEX_SET(x)    (cspinlock(x) == 0)
00135 #define MUTEX_UNSET(x)  spinunlock(x)
00136 #endif
00137 
00138 /*********************************************************************
00139  * General C library functions (POSIX 1003.1 sema_XXX).
00140  *
00141  * !!!
00142  * Never selected by autoconfig in this release (semaphore calls are known
00143  * to not work in Solaris 5.5).
00144  *********************************************************************/
00145 #ifdef HAVE_MUTEX_SEMA_INIT
00146 #include <synch.h>
00147 typedef sema_t tsl_t;
00148 
00149 #define MUTEX_ALIGN     sizeof(int)
00150 #define MUTEX_INIT(x)   (sema_init(x, 1, USYNC_PROCESS, NULL) != 0)
00151 #define MUTEX_SET(x)    (sema_wait(x) == 0)
00152 #define MUTEX_UNSET(x)  sema_post(x)
00153 #endif
00154 
00155 /*********************************************************************
00156  * SGI C library functions.
00157  *********************************************************************/
00158 #ifdef HAVE_MUTEX_SGI_INIT_LOCK
00159 #include <abi_mutex.h>
00160 typedef abilock_t tsl_t;
00161 
00162 #define MUTEX_ALIGN     sizeof(int)
00163 #define MUTEX_INIT(x)   (init_lock(x) != 0)
00164 #define MUTEX_SET(x)    (!acquire_lock(x))
00165 #define MUTEX_UNSET(x)  release_lock(x)
00166 #endif
00167 
00168 /*********************************************************************
00169  * Solaris C library functions.
00170  *
00171  * !!!
00172  * These are undocumented functions, but they're the only ones that work
00173  * correctly as far as we know.
00174  *********************************************************************/
00175 #ifdef HAVE_MUTEX_SOLARIS_LOCK_TRY
00176 #include <sys/machlock.h>
00177 typedef lock_t tsl_t;
00178 
00179 #define MUTEX_ALIGN     sizeof(int)
00180 #define MUTEX_INIT(x)   0
00181 #define MUTEX_SET(x)    _lock_try(x)
00182 #define MUTEX_UNSET(x)  _lock_clear(x)
00183 #endif
00184 
00185 /*********************************************************************
00186  * VMS.
00187  *********************************************************************/
00188 #ifdef HAVE_MUTEX_VMS
00189 #include <sys/mman.h>;
00190 #include <builtins.h>
00191 typedef unsigned char tsl_t;
00192 
00193 #define MUTEX_ALIGN             sizeof(unsigned int)
00194 #ifdef __ALPHA
00195 #define MUTEX_SET(tsl)          (!__TESTBITSSI(tsl, 0))
00196 #else /* __VAX */
00197 #define MUTEX_SET(tsl)          (!(int)_BBSSI(0, tsl))
00198 #endif
00199 #define MUTEX_UNSET(tsl)        (*(tsl) = 0)
00200 #define MUTEX_INIT(tsl)         MUTEX_UNSET(tsl)
00201 #endif
00202 
00203 /*********************************************************************
00204  * VxWorks
00205  * Use basic binary semaphores in VxWorks, as we currently do not need
00206  * any special features.  We do need the ability to single-thread the
00207  * entire system, however, because VxWorks doesn't support the open(2)
00208  * flag O_EXCL, the mechanism we normally use to single thread access
00209  * when we're first looking for a DB environment.
00210  *********************************************************************/
00211 #ifdef HAVE_MUTEX_VXWORKS
00212 #include "semLib.h"
00213 typedef SEM_ID tsl_t;
00214 
00215 #define MUTEX_ALIGN             sizeof(unsigned int)
00216 #define MUTEX_SET(tsl)          (semTake((*tsl), WAIT_FOREVER) == OK)
00217 #define MUTEX_UNSET(tsl)        (semGive((*tsl)) == OK)
00218 #define MUTEX_INIT(tsl)                                                 \
00219         ((*(tsl) = semBCreate(SEM_Q_FIFO, SEM_FULL)) == NULL)
00220 
00221 #undef  DB_BEGIN_SINGLE_THREAD
00222 /*
00223  * Use the taskLock() mutex to eliminate a race where two tasks are
00224  * trying to initialize the global lock at the same time.
00225  */
00226 #define DB_BEGIN_SINGLE_THREAD                                          \
00227 do {                                                                    \
00228         if (DB_GLOBAL(db_global_init))                                  \
00229                 (void)semTake(DB_GLOBAL(db_global_lock), WAIT_FOREVER); \
00230         else {                                                          \
00231                 taskLock();                                             \
00232                 if (DB_GLOBAL(db_global_init)) {                        \
00233                         taskUnlock();                                   \
00234                         (void)semTake(DB_GLOBAL(db_global_lock),        \
00235                             WAIT_FOREVER);                              \
00236                         continue;                                       \
00237                 }                                                       \
00238                 DB_GLOBAL(db_global_lock) =                             \
00239                     semBCreate(SEM_Q_FIFO, SEM_EMPTY);                  \
00240                 if (DB_GLOBAL(db_global_lock) != NULL)                  \
00241                         DB_GLOBAL(db_global_init) = 1;                  \
00242                 taskUnlock();                                           \
00243         }                                                               \
00244 } while (DB_GLOBAL(db_global_init) == 0)
00245 #undef  DB_END_SINGLE_THREAD
00246 #define DB_END_SINGLE_THREAD    (void)semGive(DB_GLOBAL(db_global_lock))
00247 #endif
00248 
00249 /*********************************************************************
00250  * Win16
00251  *
00252  * Win16 spinlocks are simple because we cannot possibly be preempted.
00253  *
00254  * !!!
00255  * We should simplify this by always returning a no-need-to-lock lock
00256  * when we initialize the mutex.
00257  *********************************************************************/
00258 #ifdef HAVE_MUTEX_WIN16
00259 typedef unsigned int tsl_t;
00260 
00261 #define MUTEX_ALIGN             sizeof(unsigned int)
00262 #define MUTEX_INIT(x)           0
00263 #define MUTEX_SET(tsl)          (*(tsl) = 1)
00264 #define MUTEX_UNSET(tsl)        (*(tsl) = 0)
00265 #endif
00266 
00267 /*********************************************************************
00268  * Win32
00269  *********************************************************************/
00270 #ifdef HAVE_MUTEX_WIN32
00271 typedef unsigned int tsl_t;
00272 
00273 #define MUTEX_ALIGN             sizeof(unsigned int)
00274 #define MUTEX_INIT(x)           0
00275 #define MUTEX_SET(tsl)          (!InterlockedExchange((PLONG)tsl, 1))
00276 #define MUTEX_UNSET(tsl)        (*(tsl) = 0)
00277 #endif
00278 
00279 /*********************************************************************
00280  * 68K/gcc assembly.
00281  *********************************************************************/
00282 #ifdef HAVE_MUTEX_68K_GCC_ASSEMBLY
00283 typedef unsigned char tsl_t;
00284 #endif
00285 
00286 /*********************************************************************
00287  * ALPHA/gcc assembly.
00288  *********************************************************************/
00289 #ifdef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY
00290 typedef u_int32_t tsl_t;
00291 
00292 #define MUTEX_ALIGN     4
00293 #endif
00294 
00295 /*********************************************************************
00296  * HPPA/gcc assembly.
00297  *********************************************************************/
00298 #ifdef HAVE_MUTEX_HPPA_GCC_ASSEMBLY
00299 typedef u_int32_t tsl_t;
00300 
00301 #define MUTEX_ALIGN     16
00302 #endif
00303 
00304 /*********************************************************************
00305  * IA64/gcc assembly.
00306  *********************************************************************/
00307 #ifdef HAVE_MUTEX_IA64_GCC_ASSEMBLY
00308 typedef unsigned char tsl_t;
00309 #endif
00310 
00311 /*********************************************************************
00312  * SCO/cc assembly.
00313  *********************************************************************/
00314 #ifdef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY
00315 typedef unsigned char tsl_t;
00316 #endif
00317 
00318 /*********************************************************************
00319  * Sparc/gcc assembly.
00320  *********************************************************************/
00321 #ifdef HAVE_MUTEX_SPARC_GCC_ASSEMBLY
00322 typedef unsigned char tsl_t;
00323 #endif
00324 
00325 /*********************************************************************
00326  * UTS/cc assembly.
00327  *********************************************************************/
00328 #ifdef HAVE_MUTEX_UTS_CC_ASSEMBLY
00329 typedef int tsl_t;
00330 
00331 #define MUTEX_ALIGN     sizeof(int)
00332 #define MUTEX_INIT(x)   0
00333 #define MUTEX_SET(x)    (!uts_lock(x, 1))
00334 #define MUTEX_UNSET(x)  (*(x) = 0)
00335 #endif
00336 
00337 /*********************************************************************
00338  * x86/gcc assembly.
00339  *********************************************************************/
00340 #ifdef HAVE_MUTEX_X86_GCC_ASSEMBLY
00341 typedef unsigned char tsl_t;
00342 #endif
00343 
00344 /*
00345  * Mutex alignment defaults to one byte.
00346  *
00347  * !!!
00348  * Various systems require different alignments for mutexes (the worst we've
00349  * seen so far is 16-bytes on some HP architectures).  Malloc(3) is assumed
00350  * to return reasonable alignment, all other mutex users must ensure proper
00351  * alignment locally.
00352  */
00353 #ifndef MUTEX_ALIGN
00354 #define MUTEX_ALIGN     1
00355 #endif
00356 
00357 #define MUTEX_IGNORE            0x001   /* Ignore, no lock required. */
00358 #define MUTEX_SELF_BLOCK        0x002   /* Must block self. */
00359 #define MUTEX_THREAD            0x004   /* Thread-only mutex. */
00360 
00361 /* Mutex. */
00362 struct __mutex_t {
00363 #ifdef  HAVE_MUTEX_THREADS
00364 #ifdef  MUTEX_FIELDS
00365         MUTEX_FIELDS
00366 #else
00367         tsl_t   tas;                    /* Test and set. */
00368 #endif
00369         u_int32_t spins;                /* Spins before block. */
00370         u_int32_t locked;               /* !0 if locked. */
00371 #else
00372         u_int32_t off;                  /* Byte offset to lock. */
00373         u_int32_t pid;                  /* Lock holder: 0 or process pid. */
00374 #endif
00375         u_int32_t mutex_set_wait;       /* Granted after wait. */
00376         u_int32_t mutex_set_nowait;     /* Granted without waiting. */
00377 
00378         u_int8_t  flags;                /* MUTEX_XXX */
00379 };
00380 
00381 /* Redirect calls to the correct functions. */
00382 #ifdef HAVE_MUTEX_THREADS
00383 #if defined(HAVE_MUTEX_PTHREADS) || defined(HAVE_MUTEX_SOLARIS_LWP) || defined(HAVE_MUTEX_UI_THREADS)
00384 #define __db_mutex_init(a, b, c, d)     __db_pthread_mutex_init(a, b, d)
00385 #define __db_mutex_lock(a, b)           __db_pthread_mutex_lock(a)
00386 #define __db_mutex_unlock(a)            __db_pthread_mutex_unlock(a)
00387 #else
00388 #define __db_mutex_init(a, b, c, d)     CDB___db_tas_mutex_init(a, b, d)
00389 #define __db_mutex_lock(a, b)           CDB___db_tas_mutex_lock(a)
00390 #define __db_mutex_unlock(a)            CDB___db_tas_mutex_unlock(a)
00391 #endif
00392 #else
00393 #define __db_mutex_init(a, b, c, d)     __db_fcntl_mutex_init(a, b, c)
00394 #define __db_mutex_lock(a, b)           __db_fcntl_mutex_lock(a, b)
00395 #define __db_mutex_unlock(a)            __db_fcntl_mutex_unlock(a)
00396 #endif
00397 
00398 /*
00399  * Lock/unlock a mutex.  If the mutex was marked as uninteresting, the thread
00400  * of control can proceed without it.
00401  *
00402  * If the lock is for threads-only, then it was optionally not allocated and
00403  * file handles aren't necessary, as threaded applications aren't supported by
00404  * fcntl(2) locking.
00405  */
00406 #ifdef DIAGNOSTIC
00407         /*
00408          * XXX
00409          * We want to switch threads as often as possible.  Yield every time
00410          * we get a mutex to ensure contention.
00411          */
00412 #define MUTEX_LOCK(mp, fh)                                              \
00413         if (!F_ISSET((MUTEX *)(mp), MUTEX_IGNORE))                      \
00414                 (void)__db_mutex_lock(mp, fh);                          \
00415         if (DB_GLOBAL(db_pageyield))                                    \
00416                 CDB___os_yield(NULL, 1);
00417 #else
00418 #define MUTEX_LOCK(mp, fh)                                              \
00419         if (!F_ISSET((MUTEX *)(mp), MUTEX_IGNORE))                      \
00420                 (void)__db_mutex_lock(mp, fh);
00421 #endif
00422 #define MUTEX_UNLOCK(mp)                                                \
00423         if (!F_ISSET((MUTEX *)(mp), MUTEX_IGNORE))                      \
00424                 (void)__db_mutex_unlock(mp);
00425 #define MUTEX_THREAD_LOCK(mp)                                           \
00426         if (mp != NULL)                                                 \
00427                 MUTEX_LOCK(mp, NULL)
00428 #define MUTEX_THREAD_UNLOCK(mp)                                         \
00429         if (mp != NULL)                                                 \
00430                 MUTEX_UNLOCK(mp)
00431 
00432 /*
00433  * We use a single file descriptor for fcntl(2) locking, and (generally) the
00434  * object's offset in a shared region as the byte that we're locking.  So,
00435  * there's a (remote) possibility that two objects might have the same offsets
00436  * such that the locks could conflict, resulting in deadlock.  To avoid this
00437  * possibility, we offset the region offset by a small integer value, using a
00438  * different offset for each subsystem's locks.  Since all region objects are
00439  * suitably aligned, the offset guarantees that we don't collide with another
00440  * region's objects.
00441  */
00442 #define DB_FCNTL_OFF_GEN        0               /* Everything else. */
00443 #define DB_FCNTL_OFF_LOCK       1               /* Lock subsystem offset. */
00444 #define DB_FCNTL_OFF_MPOOL      2               /* Mpool subsystem offset. */

Generated on Sun Jun 8 10:56:38 2008 for GNUmifluz by  doxygen 1.5.5