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 00008 #include "config.h" 00009 00010 #ifdef HAVE_MUTEX_TAS 00011 00012 #ifndef lint 00013 static const char revid[] = "$Id: mut__tas_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 <stdlib.h> 00021 #include <string.h> 00022 #include <unistd.h> 00023 #endif 00024 00025 #include "db_int.h" 00026 00027 #ifdef HAVE_MUTEX_68K_GCC_ASSEMBLY 00028 #include "68K.gcc" 00029 #endif 00030 #ifdef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY 00031 #include "alpha.gcc" 00032 #endif 00033 #ifdef HAVE_MUTEX_HPPA_GCC_ASSEMBLY 00034 #include "parisc.gcc" 00035 #endif 00036 #ifdef HAVE_MUTEX_IA64_GCC_ASSEMBLY 00037 #include "ia64.gcc" 00038 #endif 00039 #ifdef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY 00040 #include "sco.cc" 00041 #endif 00042 #ifdef HAVE_MUTEX_SPARC_GCC_ASSEMBLY 00043 #include "sparc.gcc" 00044 #endif 00045 #ifdef HAVE_MUTEX_X86_GCC_ASSEMBLY 00046 #include "x86.gcc" 00047 #endif 00048 00049 #ifdef DIAGNOSTIC 00050 #undef MSG1 00051 #define MSG1 "mutex_lock: ERROR: lock currently in use: pid: %lu.\n" 00052 #undef MSG2 00053 #define MSG2 "mutex_unlock: ERROR: lock already unlocked\n" 00054 #ifndef STDERR_FILENO 00055 #define STDERR_FILENO 2 00056 #endif 00057 #endif 00058 00059 /* 00060 * CDB___db_tas_mutex_init -- 00061 * Initialize a MUTEX. 00062 * 00063 * PUBLIC: int CDB___db_tas_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t)); 00064 */ 00065 int 00066 CDB___db_tas_mutex_init(dbenv, mutexp, flags) 00067 DB_ENV *dbenv; 00068 MUTEX *mutexp; 00069 u_int32_t flags; 00070 { 00071 /* Check alignment. */ 00072 DB_ASSERT(((db_alignp_t)mutexp & (MUTEX_ALIGN - 1)) == 0); 00073 00074 memset(mutexp, 0, sizeof(*mutexp)); 00075 00076 /* 00077 * If this is a thread lock or the process has told us that there are 00078 * no other processes in the environment, use thread-only locks, they 00079 * are faster in some cases. 00080 * 00081 * This is where we decide to ignore locks we don't need to set -- if 00082 * the application isn't threaded, there aren't any threads to block. 00083 */ 00084 if (LF_ISSET(MUTEX_THREAD) || F_ISSET(dbenv, DB_ENV_PRIVATE)) { 00085 if (!F_ISSET(dbenv, DB_ENV_THREAD)) { 00086 F_SET(mutexp, MUTEX_IGNORE); 00087 return (0); 00088 } 00089 F_SET(mutexp, MUTEX_THREAD); 00090 } 00091 00092 /* Initialize the lock. */ 00093 if (MUTEX_INIT(&mutexp->tas)) 00094 return (CDB___os_get_errno()); 00095 00096 mutexp->spins = CDB___os_spin(); 00097 00098 return (0); 00099 } 00100 00101 /* 00102 * CDB___db_tas_mutex_lock 00103 * Lock on a mutex, logically blocking if necessary. 00104 * 00105 * PUBLIC: int CDB___db_tas_mutex_lock __P((MUTEX *)); 00106 */ 00107 int 00108 CDB___db_tas_mutex_lock(mutexp) 00109 MUTEX *mutexp; 00110 { 00111 u_long ms; 00112 int nspins; 00113 00114 if (!DB_GLOBAL(db_mutexlocks) || F_ISSET(mutexp, MUTEX_IGNORE)) 00115 return (0); 00116 00117 ms = 1; 00118 00119 loop: /* Attempt to acquire the resource for N spins. */ 00120 for (nspins = mutexp->spins; nspins > 0; --nspins) { 00121 #ifdef HAVE_MUTEX_HPPA_MSEM_INIT 00122 relock: 00123 #endif 00124 if (!MUTEX_SET(&mutexp->tas)) 00125 continue; 00126 #ifdef HAVE_MUTEX_HPPA_MSEM_INIT 00127 /* 00128 * HP semaphores are unlocked automatically when a holding 00129 * process exits. If the mutex appears to be locked 00130 * (mutexp->locked != 0) but we got here, assume this has 00131 * happened. Stick our own pid into mutexp->locked and 00132 * lock again. (The default state of the mutexes used to 00133 * block in __lock_get_internal is locked, so exiting with 00134 * a locked mutex is reasonable behavior for a process that 00135 * happened to initialize or use one of them.) 00136 */ 00137 if (mutexp->locked != 0) { 00138 mutexp->locked = (u_int32_t)getpid(); 00139 goto relock; 00140 } 00141 /* 00142 * If we make it here, locked == 0, the diagnostic won't fire, 00143 * and we were really unlocked by someone calling the 00144 * DB mutex unlock function. 00145 */ 00146 #endif 00147 #ifdef DIAGNOSTIC 00148 if (mutexp->locked != 0) { 00149 char msgbuf[128]; 00150 (void)snprintf(msgbuf, 00151 sizeof(msgbuf), MSG1, (u_long)mutexp->locked); 00152 (void)write(STDERR_FILENO, msgbuf, strlen(msgbuf)); 00153 } 00154 #endif 00155 #if defined(DIAGNOSTIC) || defined(HAVE_MUTEX_HPPA_MSEM_INIT) 00156 mutexp->locked = (u_int32_t)getpid(); 00157 #endif 00158 if (ms == 1) 00159 ++mutexp->mutex_set_nowait; 00160 else 00161 ++mutexp->mutex_set_wait; 00162 return (0); 00163 } 00164 00165 /* Yield the processor; wait 1ms initially, up to 1 second. */ 00166 CDB___os_yield(NULL, ms * USEC_PER_MS); 00167 if ((ms <<= 1) > MS_PER_SEC) 00168 ms = MS_PER_SEC; 00169 00170 goto loop; 00171 } 00172 00173 /* 00174 * CDB___db_tas_mutex_unlock -- 00175 * Release a lock. 00176 * 00177 * PUBLIC: int CDB___db_tas_mutex_unlock __P((MUTEX *)); 00178 */ 00179 int 00180 CDB___db_tas_mutex_unlock(mutexp) 00181 MUTEX *mutexp; 00182 { 00183 if (!DB_GLOBAL(db_mutexlocks) || F_ISSET(mutexp, MUTEX_IGNORE)) 00184 return (0); 00185 00186 #ifdef DIAGNOSTIC 00187 if (!mutexp->locked) 00188 (void)write(STDERR_FILENO, MSG2, sizeof(MSG2) - 1); 00189 #endif 00190 #if defined(DIAGNOSTIC) || defined(HAVE_MUTEX_HPPA_MSEM_INIT) 00191 mutexp->locked = 0; 00192 #endif 00193 00194 MUTEX_UNSET(&mutexp->tas); 00195 00196 return (0); 00197 } 00198 #endif /* HAVE_MUTEX_TAS */