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

mut_pthread.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1999-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: mut_pthread.c,v 12.12 2005/11/01 00:44:27 bostic 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 #include "dbinc/mutex_int.h"
00020 
00021 #ifdef HAVE_MUTEX_SOLARIS_LWP
00022 #define pthread_cond_destroy(x)         0
00023 #define pthread_cond_signal             _lwp_cond_signal
00024 #define pthread_cond_wait               _lwp_cond_wait
00025 #define pthread_mutex_destroy(x)        0
00026 #define pthread_mutex_lock              _lwp_mutex_lock
00027 #define pthread_mutex_trylock           _lwp_mutex_trylock
00028 #define pthread_mutex_unlock            _lwp_mutex_unlock
00029 #endif
00030 #ifdef HAVE_MUTEX_UI_THREADS
00031 #define pthread_cond_destroy(x)         cond_destroy
00032 #define pthread_cond_signal             cond_signal
00033 #define pthread_cond_wait               cond_wait
00034 #define pthread_mutex_destroy           mutex_destroy
00035 #define pthread_mutex_lock              mutex_lock
00036 #define pthread_mutex_trylock           mutex_trylock
00037 #define pthread_mutex_unlock            mutex_unlock
00038 #endif
00039 
00040 #define PTHREAD_UNLOCK_ATTEMPTS 5
00041 
00042 /*
00043  * IBM's MVS pthread mutex implementation returns -1 and sets errno rather than
00044  * returning errno itself.  As -1 is not a valid errno value, assume functions
00045  * returning -1 have set errno.  If they haven't, return a random error value.
00046  */
00047 #define RET_SET(f, ret) do {                                            \
00048         if (((ret) = (f)) == -1 && ((ret) = errno) == 0)                \
00049                 (ret) = EAGAIN;                                         \
00050 } while (0)
00051 
00052 /*
00053  * __db_pthread_mutex_init --
00054  *      Initialize a pthread mutex.
00055  *
00056  * PUBLIC: int __db_pthread_mutex_init __P((DB_ENV *, db_mutex_t, u_int32_t));
00057  */
00058 int
00059 __db_pthread_mutex_init(dbenv, mutex, flags)
00060         DB_ENV *dbenv;
00061         db_mutex_t mutex;
00062         u_int32_t flags;
00063 {
00064         DB_MUTEX *mutexp;
00065         DB_MUTEXMGR *mtxmgr;
00066         DB_MUTEXREGION *mtxregion;
00067         int ret;
00068 
00069         mtxmgr = dbenv->mutex_handle;
00070         mtxregion = mtxmgr->reginfo.primary;
00071         mutexp = MUTEXP_SET(mutex);
00072         ret = 0;
00073 
00074 #ifdef HAVE_MUTEX_PTHREADS
00075         {
00076         pthread_condattr_t condattr, *condattrp = NULL;
00077         pthread_mutexattr_t mutexattr, *mutexattrp = NULL;
00078 
00079         if (!LF_ISSET(DB_MUTEX_THREAD)) {
00080                 RET_SET((pthread_mutexattr_init(&mutexattr)), ret);
00081 #ifndef HAVE_MUTEX_THREAD_ONLY
00082                 if (ret == 0)
00083                         RET_SET((pthread_mutexattr_setpshared(
00084                             &mutexattr, PTHREAD_PROCESS_SHARED)), ret);
00085 #endif
00086                 mutexattrp = &mutexattr;
00087         }
00088 
00089         if (ret == 0)
00090                 RET_SET((pthread_mutex_init(&mutexp->mutex, mutexattrp)), ret);
00091         if (mutexattrp != NULL)
00092                 (void)pthread_mutexattr_destroy(mutexattrp);
00093         if (ret == 0 && LF_ISSET(DB_MUTEX_SELF_BLOCK)) {
00094                 if (!LF_ISSET(DB_MUTEX_THREAD)) {
00095                         RET_SET((pthread_condattr_init(&condattr)), ret);
00096                         if (ret == 0) {
00097                                 condattrp = &condattr;
00098 #ifndef HAVE_MUTEX_THREAD_ONLY
00099                                 RET_SET((pthread_condattr_setpshared(
00100                                     &condattr, PTHREAD_PROCESS_SHARED)), ret);
00101 #endif
00102                         }
00103                 }
00104 
00105                 if (ret == 0)
00106                         RET_SET(
00107                             (pthread_cond_init(&mutexp->cond, condattrp)), ret);
00108 
00109                 F_SET(mutexp, DB_MUTEX_SELF_BLOCK);
00110                 if (condattrp != NULL)
00111                         (void)pthread_condattr_destroy(condattrp);
00112         }
00113 
00114         }
00115 #endif
00116 #ifdef HAVE_MUTEX_SOLARIS_LWP
00117         /*
00118          * XXX
00119          * Gcc complains about missing braces in the static initializations of
00120          * lwp_cond_t and lwp_mutex_t structures because the structures contain
00121          * sub-structures/unions and the Solaris include file that defines the
00122          * initialization values doesn't have surrounding braces.  There's not
00123          * much we can do.
00124          */
00125         if (LF_ISSET(DB_MUTEX_THREAD)) {
00126                 static lwp_mutex_t mi = DEFAULTMUTEX;
00127 
00128                 mutexp->mutex = mi;
00129         } else {
00130                 static lwp_mutex_t mi = SHAREDMUTEX;
00131 
00132                 mutexp->mutex = mi;
00133         }
00134         if (LF_ISSET(DB_MUTEX_SELF_BLOCK)) {
00135                 if (LF_ISSET(DB_MUTEX_THREAD)) {
00136                         static lwp_cond_t ci = DEFAULTCV;
00137 
00138                         mutexp->cond = ci;
00139                 } else {
00140                         static lwp_cond_t ci = SHAREDCV;
00141 
00142                         mutexp->cond = ci;
00143                 }
00144                 F_SET(mutexp, DB_MUTEX_SELF_BLOCK);
00145         }
00146 #endif
00147 #ifdef HAVE_MUTEX_UI_THREADS
00148         {
00149         int type;
00150 
00151         type = LF_ISSET(DB_MUTEX_THREAD) ? USYNC_THREAD : USYNC_PROCESS;
00152 
00153         ret = mutex_init(&mutexp->mutex, type, NULL);
00154         if (ret == 0 && LF_ISSET(DB_MUTEX_SELF_BLOCK)) {
00155                 ret = cond_init(&mutexp->cond, type, NULL);
00156 
00157                 F_SET(mutexp, DB_MUTEX_SELF_BLOCK);
00158         }}
00159 #endif
00160 
00161         if (ret != 0) {
00162                 __db_err(dbenv,
00163                     "unable to initialize mutex: %s", strerror(ret));
00164         }
00165         return (ret);
00166 }
00167 
00168 /*
00169  * __db_pthread_mutex_lock
00170  *      Lock on a mutex, blocking if necessary.
00171  *
00172  * PUBLIC: int __db_pthread_mutex_lock __P((DB_ENV *, db_mutex_t));
00173  */
00174 int
00175 __db_pthread_mutex_lock(dbenv, mutex)
00176         DB_ENV *dbenv;
00177         db_mutex_t mutex;
00178 {
00179         DB_MUTEX *mutexp;
00180         DB_MUTEXMGR *mtxmgr;
00181         DB_MUTEXREGION *mtxregion;
00182         int i, ret;
00183 
00184         if (!MUTEX_ON(dbenv) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
00185                 return (0);
00186 
00187         mtxmgr = dbenv->mutex_handle;
00188         mtxregion = mtxmgr->reginfo.primary;
00189         mutexp = MUTEXP_SET(mutex);
00190 
00191 #ifdef HAVE_STATISTICS
00192         /*
00193          * We want to know which mutexes are contentious, but don't want to
00194          * do an interlocked test here -- that's slower when the underlying
00195          * system has adaptive mutexes and can perform optimizations like
00196          * spinning only if the thread holding the mutex is actually running
00197          * on a CPU.  Make a guess, using a normal load instruction.
00198          */
00199         if (F_ISSET(mutexp, DB_MUTEX_LOCKED))
00200                 ++mutexp->mutex_set_wait;
00201         else
00202                 ++mutexp->mutex_set_nowait;
00203 #endif
00204 
00205         RET_SET((pthread_mutex_lock(&mutexp->mutex)), ret);
00206         if (ret != 0)
00207                 goto err;
00208 
00209         if (F_ISSET(mutexp, DB_MUTEX_SELF_BLOCK)) {
00210                 while (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
00211                         RET_SET((pthread_cond_wait(
00212                             &mutexp->cond, &mutexp->mutex)), ret);
00213                         /*
00214                          * !!!
00215                          * Solaris bug workaround:
00216                          * pthread_cond_wait() sometimes returns ETIME -- out
00217                          * of sheer paranoia, check both ETIME and ETIMEDOUT.
00218                          * We believe this happens when the application uses
00219                          * SIGALRM for some purpose, e.g., the C library sleep
00220                          * call, and Solaris delivers the signal to the wrong
00221                          * LWP.
00222                          */
00223                         if (ret != 0 && ret != EINTR &&
00224 #ifdef ETIME
00225                             ret != ETIME &&
00226 #endif
00227                             ret != ETIMEDOUT) {
00228                                 (void)pthread_mutex_unlock(&mutexp->mutex);
00229                                 goto err;
00230                         }
00231                 }
00232 
00233                 F_SET(mutexp, DB_MUTEX_LOCKED);
00234                 dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid);
00235                 CHECK_MTX_THREAD(dbenv, mutexp);
00236 
00237                 /*
00238                  * According to HP-UX engineers contacted by Netscape,
00239                  * pthread_mutex_unlock() will occasionally return EFAULT
00240                  * for no good reason on mutexes in shared memory regions,
00241                  * and the correct caller behavior is to try again.  Do
00242                  * so, up to PTHREAD_UNLOCK_ATTEMPTS consecutive times.
00243                  * Note that we don't bother to restrict this to HP-UX;
00244                  * it should be harmless elsewhere. [#2471]
00245                  */
00246                 i = PTHREAD_UNLOCK_ATTEMPTS;
00247                 do {
00248                         RET_SET((pthread_mutex_unlock(&mutexp->mutex)), ret);
00249                 } while (ret == EFAULT && --i > 0);
00250                 if (ret != 0)
00251                         goto err;
00252         } else {
00253 #ifdef DIAGNOSTIC
00254                 if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
00255                         char buf[DB_THREADID_STRLEN];
00256                         (void)dbenv->thread_id_string(dbenv,
00257                             mutexp->pid, mutexp->tid, buf);
00258                         __db_err(dbenv,
00259                     "pthread lock failed: lock currently in use: pid/tid: %s",
00260                             buf);
00261                         ret = EINVAL;
00262                         goto err;
00263                 }
00264 #endif
00265                 F_SET(mutexp, DB_MUTEX_LOCKED);
00266                 dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid);
00267                 CHECK_MTX_THREAD(dbenv, mutexp);
00268         }
00269 
00270 #ifdef DIAGNOSTIC
00271         /*
00272          * We want to switch threads as often as possible.  Yield every time
00273          * we get a mutex to ensure contention.
00274          */
00275         if (F_ISSET(dbenv, DB_ENV_YIELDCPU))
00276                 __os_yield(NULL, 1);
00277 #endif
00278         return (0);
00279 
00280 err:    __db_err(dbenv, "pthread lock failed: %s", db_strerror(ret));
00281         return (__db_panic(dbenv, ret));
00282 }
00283 
00284 /*
00285  * __db_pthread_mutex_unlock --
00286  *      Release a mutex.
00287  *
00288  * PUBLIC: int __db_pthread_mutex_unlock __P((DB_ENV *, db_mutex_t));
00289  */
00290 int
00291 __db_pthread_mutex_unlock(dbenv, mutex)
00292         DB_ENV *dbenv;
00293         db_mutex_t mutex;
00294 {
00295         DB_MUTEX *mutexp;
00296         DB_MUTEXMGR *mtxmgr;
00297         DB_MUTEXREGION *mtxregion;
00298         int i, ret;
00299 
00300         if (!MUTEX_ON(dbenv) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
00301                 return (0);
00302 
00303         mtxmgr = dbenv->mutex_handle;
00304         mtxregion = mtxmgr->reginfo.primary;
00305         mutexp = MUTEXP_SET(mutex);
00306 
00307 #ifdef DIAGNOSTIC
00308         if (!F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
00309                 __db_err(dbenv, "pthread unlock failed: lock already unlocked");
00310                 return (__db_panic(dbenv, EACCES));
00311         }
00312 #endif
00313         if (F_ISSET(mutexp, DB_MUTEX_SELF_BLOCK)) {
00314                 RET_SET((pthread_mutex_lock(&mutexp->mutex)), ret);
00315                 if (ret != 0)
00316                         goto err;
00317 
00318                 F_CLR(mutexp, DB_MUTEX_LOCKED);
00319 
00320                 RET_SET((pthread_cond_signal(&mutexp->cond)), ret);
00321                 if (ret != 0)
00322                         goto err;
00323         } else
00324                 F_CLR(mutexp, DB_MUTEX_LOCKED);
00325 
00326         /* See comment above;  workaround for [#2471]. */
00327         i = PTHREAD_UNLOCK_ATTEMPTS;
00328         do {
00329                 RET_SET((pthread_mutex_unlock(&mutexp->mutex)), ret);
00330         } while (ret == EFAULT && --i > 0);
00331 
00332 err:    if (ret != 0) {
00333                 __db_err(dbenv, "pthread unlock failed: %s", db_strerror(ret));
00334                 return (__db_panic(dbenv, ret));
00335         }
00336         return (ret);
00337 }
00338 
00339 /*
00340  * __db_pthread_mutex_destroy --
00341  *      Destroy a mutex.
00342  *
00343  * PUBLIC: int __db_pthread_mutex_destroy __P((DB_ENV *, db_mutex_t));
00344  */
00345 int
00346 __db_pthread_mutex_destroy(dbenv, mutex)
00347         DB_ENV *dbenv;
00348         db_mutex_t mutex;
00349 {
00350         DB_MUTEX *mutexp;
00351         DB_MUTEXMGR *mtxmgr;
00352         DB_MUTEXREGION *mtxregion;
00353         int ret, t_ret;
00354 
00355         if (!MUTEX_ON(dbenv))
00356                 return (0);
00357 
00358         mtxmgr = dbenv->mutex_handle;
00359         mtxregion = mtxmgr->reginfo.primary;
00360         mutexp = MUTEXP_SET(mutex);
00361 
00362         ret = 0;
00363         if (F_ISSET(mutexp, DB_MUTEX_SELF_BLOCK)) {
00364                 RET_SET((pthread_cond_destroy(&mutexp->cond)), ret);
00365                 if (ret != 0)
00366                         __db_err(NULL,
00367                             "unable to destroy cond: %s", strerror(ret));
00368         }
00369         RET_SET((pthread_mutex_destroy(&mutexp->mutex)), t_ret);
00370         if (t_ret != 0) {
00371                 __db_err(NULL, "unable to destroy mutex: %s", strerror(t_ret));
00372                 if (ret == 0)
00373                         ret = t_ret;
00374         }
00375         return (ret);
00376 }

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