00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 00008 #include "config.h" 00009 00010 #ifdef HAVE_MUTEX_PTHREAD 00011 00012 #ifndef lint 00013 static const char revid[] = "$Id: mut__pthread_8c-source.html,v 1.1 2008年06月08日 10:20:55 sebdiaz Exp $"; 00014 #endif /* not lint */ 00015 00016 #ifndef NO_SYSTEM_INCLUDES 00017 #include <sys/types.h> 00018 00019 #include <errno.h> 00020 #include <string.h> 00021 #include <unistd.h> 00022 #endif 00023 00024 #include "db_int.h" 00025 00026 #ifdef DIAGNOSTIC 00027 #undef MSG1 00028 #define MSG1 "mutex_lock: ERROR: lock currently in use: pid: %lu.\n" 00029 #undef MSG2 00030 #define MSG2 "mutex_unlock: ERROR: lock already unlocked\n" 00031 #ifndef STDERR_FILENO 00032 #define STDERR_FILENO 2 00033 #endif 00034 #endif 00035 00036 #ifdef HAVE_MUTEX_SOLARIS_LWP 00037 #define pthread_cond_signal _lwp_cond_signal 00038 #define pthread_cond_wait _lwp_cond_wait 00039 #define pthread_mutex_lock _lwp_mutex_lock 00040 #define pthread_mutex_trylock _lwp_mutex_trylock 00041 #define pthread_mutex_unlock _lwp_mutex_unlock 00042 #define pthread_self _lwp_self 00043 #endif 00044 #ifdef HAVE_MUTEX_UI_THREADS 00045 #define pthread_cond_signal cond_signal 00046 #define pthread_cond_wait cond_wait 00047 #define pthread_mutex_lock mutex_lock 00048 #define pthread_mutex_trylock mutex_trylock 00049 #define pthread_mutex_unlock mutex_unlock 00050 #define pthread_self thr_self 00051 #endif 00052 00053 /* 00054 * __db_pthread_mutex_init -- 00055 * Initialize a MUTEX. 00056 * 00057 * PUBLIC: int __db_pthread_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t)); 00058 */ 00059 int 00060 __db_pthread_mutex_init(dbenv, mutexp, flags) 00061 DB_ENV *dbenv; 00062 MUTEX *mutexp; 00063 u_int32_t flags; 00064 { 00065 int ret; 00066 00067 ret = 0; 00068 memset(mutexp, 0, sizeof(*mutexp)); 00069 00070 /* 00071 * If this is a thread lock or the process has told us that there are 00072 * no other processes in the environment, use thread-only locks, they 00073 * are faster in some cases. 00074 * 00075 * This is where we decide to ignore locks we don't need to set -- if 00076 * the application isn't threaded, there aren't any threads to block. 00077 */ 00078 if (LF_ISSET(MUTEX_THREAD) || F_ISSET(dbenv, DB_ENV_PRIVATE)) { 00079 if (!F_ISSET(dbenv, DB_ENV_THREAD)) { 00080 F_SET(mutexp, MUTEX_IGNORE); 00081 return (0); 00082 } 00083 F_SET(mutexp, MUTEX_THREAD); 00084 } 00085 00086 #ifdef HAVE_MUTEX_PTHREADS 00087 { 00088 pthread_condattr_t condattr, *condattrp = NULL; 00089 pthread_mutexattr_t mutexattr, *mutexattrp = NULL; 00090 00091 if (!F_ISSET(mutexp, MUTEX_THREAD)) { 00092 ret = pthread_condattr_init(&condattr); 00093 if (ret == 0) 00094 ret = pthread_condattr_setpshared( 00095 &condattr, PTHREAD_PROCESS_SHARED); 00096 condattrp = &condattr; 00097 00098 if (ret == 0) 00099 ret = pthread_mutexattr_init(&mutexattr); 00100 if (ret == 0) 00101 ret = pthread_mutexattr_setpshared( 00102 &mutexattr, PTHREAD_PROCESS_SHARED); 00103 mutexattrp = &mutexattr; 00104 } 00105 00106 if (ret == 0) 00107 ret = pthread_mutex_init(&mutexp->mutex, mutexattrp); 00108 if (mutexattrp != NULL) 00109 pthread_mutexattr_destroy(mutexattrp); 00110 if (LF_ISSET(MUTEX_SELF_BLOCK)) { 00111 if (ret == 0) 00112 ret = pthread_cond_init(&mutexp->cond, condattrp); 00113 00114 F_SET(mutexp, MUTEX_SELF_BLOCK); 00115 if (condattrp != NULL) 00116 pthread_condattr_destroy(condattrp); 00117 }} 00118 #endif 00119 #ifdef HAVE_MUTEX_SOLARIS_LWP 00120 /* 00121 * XXX 00122 * Gcc complains about missing braces in the static initializations of 00123 * lwp_cond_t and lwp_mutex_t structures because the structures contain 00124 * sub-structures/unions and the Solaris include file that defines the 00125 * initialization values doesn't have surrounding braces. There's not 00126 * much we can do. 00127 */ 00128 if (F_ISSET(mutexp, MUTEX_THREAD)) { 00129 static lwp_mutex_t mi = DEFAULTMUTEX; 00130 00131 mutexp->mutex = mi; 00132 } else { 00133 static lwp_mutex_t mi = SHAREDMUTEX; 00134 00135 mutexp->mutex = mi; 00136 } 00137 if (LF_ISSET(MUTEX_SELF_BLOCK)) { 00138 if (F_ISSET(mutexp, MUTEX_THREAD)) { 00139 static lwp_cond_t ci = DEFAULTCV; 00140 00141 mutexp->cond = ci; 00142 } else { 00143 static lwp_cond_t ci = SHAREDCV; 00144 00145 mutexp->cond = ci; 00146 } 00147 F_SET(mutexp, MUTEX_SELF_BLOCK); 00148 } 00149 #endif 00150 #ifdef HAVE_MUTEX_UI_THREADS 00151 { 00152 int type; 00153 00154 type = F_ISSET(mutexp, MUTEX_THREAD) ? USYNC_THREAD : USYNC_PROCESS; 00155 00156 ret = mutex_init(&mutexp->mutex, type, NULL); 00157 if (ret == 0 && LF_ISSET(MUTEX_SELF_BLOCK)) { 00158 ret = cond_init(&mutexp->cond, type, NULL); 00159 00160 F_SET(mutexp, MUTEX_SELF_BLOCK); 00161 }} 00162 #endif 00163 00164 mutexp->spins = CDB___os_spin(); 00165 00166 return (ret); 00167 } 00168 00169 /* 00170 * __db_pthread_mutex_lock 00171 * Lock on a mutex, logically blocking if necessary. 00172 * 00173 * PUBLIC: int __db_pthread_mutex_lock __P((MUTEX *)); 00174 */ 00175 int 00176 __db_pthread_mutex_lock(mutexp) 00177 MUTEX *mutexp; 00178 { 00179 u_int32_t nspins; 00180 int ret, waited; 00181 00182 if (!DB_GLOBAL(db_mutexlocks) || F_ISSET(mutexp, MUTEX_IGNORE)) 00183 return (0); 00184 00185 /* Attempt to acquire the resource for N spins. */ 00186 for (nspins = mutexp->spins; nspins > 0; --nspins) 00187 if (pthread_mutex_trylock(&mutexp->mutex) == 0) 00188 break; 00189 00190 if (nspins == 0 && (ret = pthread_mutex_lock(&mutexp->mutex)) != 0) 00191 return (ret); 00192 00193 if (F_ISSET(mutexp, MUTEX_SELF_BLOCK)) { 00194 for (waited = 0; mutexp->locked != 0; waited = 1) { 00195 ret = pthread_cond_wait(&mutexp->cond, &mutexp->mutex); 00196 /* 00197 * !!! 00198 * Solaris bug workaround: 00199 * pthread_cond_wait() sometimes returns ETIME -- out 00200 * of sheer paranoia, check both ETIME and ETIMEDOUT. 00201 * We believe this happens when the application uses 00202 * SIGALRM for some purpose, e.g., the C library sleep 00203 * call, and Solaris delivers the signal to the wrong 00204 * LWP. 00205 */ 00206 if (ret != 0 && ret != ETIME && ret != ETIMEDOUT) 00207 return (ret); 00208 } 00209 00210 if (waited) 00211 ++mutexp->mutex_set_wait; 00212 else 00213 ++mutexp->mutex_set_nowait; 00214 00215 #ifdef DIAGNOSTIC 00216 mutexp->locked = (u_int32_t)pthread_self(); 00217 #else 00218 mutexp->locked = 1; 00219 #endif 00220 if ((ret = pthread_mutex_unlock(&mutexp->mutex)) != 0) 00221 return (ret); 00222 } else { 00223 if (nspins == mutexp->spins) 00224 ++mutexp->mutex_set_nowait; 00225 else 00226 ++mutexp->mutex_set_wait; 00227 #ifdef DIAGNOSTIC 00228 if (mutexp->locked) { 00229 char msgbuf[128]; 00230 (void)snprintf(msgbuf, 00231 sizeof(msgbuf), MSG1, (u_long)mutexp->locked); 00232 (void)write(STDERR_FILENO, msgbuf, strlen(msgbuf)); 00233 } 00234 mutexp->locked = (u_int32_t)pthread_self(); 00235 #else 00236 mutexp->locked = 1; 00237 #endif 00238 } 00239 return (0); 00240 } 00241 00242 /* 00243 * __db_pthread_mutex_unlock -- 00244 * Release a lock. 00245 * 00246 * PUBLIC: int __db_pthread_mutex_unlock __P((MUTEX *)); 00247 */ 00248 int 00249 __db_pthread_mutex_unlock(mutexp) 00250 MUTEX *mutexp; 00251 { 00252 int ret; 00253 00254 if (!DB_GLOBAL(db_mutexlocks) || F_ISSET(mutexp, MUTEX_IGNORE)) 00255 return (0); 00256 00257 #ifdef DIAGNOSTIC 00258 if (!mutexp->locked) 00259 (void)write(STDERR_FILENO, MSG2, sizeof(MSG2) - 1); 00260 #endif 00261 00262 if (F_ISSET(mutexp, MUTEX_SELF_BLOCK)) { 00263 if ((ret = pthread_mutex_lock(&mutexp->mutex)) != 0) 00264 return (ret); 00265 00266 mutexp->locked = 0; 00267 00268 if ((ret = pthread_mutex_unlock(&mutexp->mutex)) != 0) 00269 return (ret); 00270 00271 if ((ret = pthread_cond_signal(&mutexp->cond)) != 0) 00272 return (ret); 00273 } else { 00274 mutexp->locked = 0; 00275 00276 if ((ret = pthread_mutex_unlock(&mutexp->mutex)) != 0) 00277 return (ret); 00278 } 00279 00280 return (0); 00281 } 00282 00283 #endif /* HAVE_MUTEX_PTHREAD */