1 /* 2 ** 2007 August 14 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ************************************************************************* 12 ** This file contains the C functions that implement mutexes. 13 ** 14 ** The implementation in this file does not provide any mutual 15 ** exclusion and is thus suitable for use only in applications 16 ** that use SQLite in a single thread. But this implementation 17 ** does do a lot of error checking on mutexes to make sure they 18 ** are called correctly and at appropriate times. Hence, this 19 ** implementation is suitable for testing. 20 ** debugging purposes 21 ** 22 ** $Id: mutex.c,v 1.26 2008/06/18 18:57:42 danielk1977 Exp $ 23 */ 24 #include "sqliteInt.h" 25 26 #ifndef SQLITE_MUTEX_NOOP 27 /* 28 ** Initialize the mutex system. 29 */ 30 int sqlite3MutexInit(void){ 31 int rc = SQLITE_OK; 32 if( sqlite3Config.bCoreMutex ){ 33 if( !sqlite3Config.mutex.xMutexAlloc ){ 34 /* If the xMutexAlloc method has not been set, then the user did not 35 ** install a mutex implementation via sqlite3_config() prior to 36 ** sqlite3_initialize() being called. This block copies pointers to 37 ** the default implementation into the sqlite3Config structure. 38 ** 39 ** The danger is that although sqlite3_config() is not a threadsafe 40 ** API, sqlite3_initialize() is, and so multiple threads may be 41 ** attempting to run this function simultaneously. To guard write 42 ** access to the sqlite3Config structure, the 'MASTER' static mutex 43 ** is obtained before modifying it. 44 */ 45 sqlite3_mutex_methods *p = sqlite3DefaultMutex(); 46 sqlite3_mutex *pMaster = 0; 47 48 rc = p->xMutexInit(); 49 if( rc==SQLITE_OK ){ 50 pMaster = p->xMutexAlloc(SQLITE_MUTEX_STATIC_MASTER); 51 assert(pMaster); 52 p->xMutexEnter(pMaster); 53 assert( sqlite3Config.mutex.xMutexAlloc==0 54 || sqlite3Config.mutex.xMutexAlloc==p->xMutexAlloc 55 ); 56 if( !sqlite3Config.mutex.xMutexAlloc ){ 57 sqlite3Config.mutex = *p; 58 } 59 p->xMutexLeave(pMaster); 60 } 61 }else{ 62 rc = sqlite3Config.mutex.xMutexInit(); 63 } 64 } 65 66 return rc; 67 } 68 69 /* 70 ** Shutdown the mutex system. This call frees resources allocated by 71 ** sqlite3MutexInit(). 72 */ 73 int sqlite3MutexEnd(void){ 74 int rc = SQLITE_OK; 75 rc = sqlite3Config.mutex.xMutexEnd(); 76 return rc; 77 } 78 79 /* 80 ** Retrieve a pointer to a static mutex or allocate a new dynamic one. 81 */ 82 sqlite3_mutex *sqlite3_mutex_alloc(int id){ 83 #ifndef SQLITE_OMIT_AUTOINIT 84 if( sqlite3_initialize() ) return 0; 85 #endif 86 return sqlite3Config.mutex.xMutexAlloc(id); 87 } 88 89 sqlite3_mutex *sqlite3MutexAlloc(int id){ 90 if( !sqlite3Config.bCoreMutex ){ 91 return 0; 92 } 93 return sqlite3Config.mutex.xMutexAlloc(id); 94 } 95 96 /* 97 ** Free a dynamic mutex. 98 */ 99 void sqlite3_mutex_free(sqlite3_mutex *p){ 100 if( p ){ 101 sqlite3Config.mutex.xMutexFree(p); 102 } 103 } 104 105 /* 106 ** Obtain the mutex p. If some other thread already has the mutex, block 107 ** until it can be obtained. 108 */ 109 void sqlite3_mutex_enter(sqlite3_mutex *p){ 110 if( p ){ 111 sqlite3Config.mutex.xMutexEnter(p); 112 } 113 } 114 115 /* 116 ** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another 117 ** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY. 118 */ 119 int sqlite3_mutex_try(sqlite3_mutex *p){ 120 int rc = SQLITE_OK; 121 if( p ){ 122 return sqlite3Config.mutex.xMutexTry(p); 123 } 124 return rc; 125 } 126 127 /* 128 ** The sqlite3_mutex_leave() routine exits a mutex that was previously 129 ** entered by the same thread. The behavior is undefined if the mutex 130 ** is not currently entered. If a NULL pointer is passed as an argument 131 ** this function is a no-op. 132 */ 133 void sqlite3_mutex_leave(sqlite3_mutex *p){ 134 if( p ){ 135 sqlite3Config.mutex.xMutexLeave(p); 136 } 137 } 138 139 #ifndef NDEBUG 140 /* 141 ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are 142 ** intended for use inside assert() statements. 143 */ 144 int sqlite3_mutex_held(sqlite3_mutex *p){ 145 return p==0 || sqlite3Config.mutex.xMutexHeld(p); 146 } 147 int sqlite3_mutex_notheld(sqlite3_mutex *p){ 148 return p==0 || sqlite3Config.mutex.xMutexNotheld(p); 149 } 150 #endif 151 152 #endif 153 154 #ifdef SQLITE_MUTEX_NOOP_DEBUG 155 /* 156 ** In this implementation, mutexes do not provide any mutual exclusion. 157 ** But the error checking is provided. This implementation is useful 158 ** for test purposes. 159 */ 160 161 /* 162 ** The mutex object 163 */ 164 struct sqlite3_mutex { 165 int id; /* The mutex type */ 166 int cnt; /* Number of entries without a matching leave */ 167 }; 168 169 /* 170 ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are 171 ** intended for use inside assert() statements. 172 */ 173 static int noopMutexHeld(sqlite3_mutex *p){ 174 return p==0 || p->cnt>0; 175 } 176 static int noopMutexNotheld(sqlite3_mutex *p){ 177 return p==0 || p->cnt==0; 178 } 179 180 /* 181 ** Initialize and deinitialize the mutex subsystem. 182 */ 183 static int noopMutexInit(void){ return SQLITE_OK; } 184 static int noopMutexEnd(void){ return SQLITE_OK; } 185 186 /* 187 ** The sqlite3_mutex_alloc() routine allocates a new 188 ** mutex and returns a pointer to it. If it returns NULL 189 ** that means that a mutex could not be allocated. 190 */ 191 static sqlite3_mutex *noopMutexAlloc(int id){ 192 static sqlite3_mutex aStatic[6]; 193 sqlite3_mutex *pNew = 0; 194 switch( id ){ 195 case SQLITE_MUTEX_FAST: 196 case SQLITE_MUTEX_RECURSIVE: { 197 pNew = sqlite3Malloc(sizeof(*pNew)); 198 if( pNew ){ 199 pNew->id = id; 200 pNew->cnt = 0; 201 } 202 break; 203 } 204 default: { 205 assert( id-2 >= 0 ); 206 assert( id-2 < sizeof(aStatic)/sizeof(aStatic[0]) ); 207 pNew = &aStatic[id-2]; 208 pNew->id = id; 209 break; 210 } 211 } 212 return pNew; 213 } 214 215 /* 216 ** This routine deallocates a previously allocated mutex. 217 */ 218 static void noopMutexFree(sqlite3_mutex *p){ 219 assert( p->cnt==0 ); 220 assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); 221 sqlite3_free(p); 222 } 223 224 /* 225 ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt 226 ** to enter a mutex. If another thread is already within the mutex, 227 ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return 228 ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK 229 ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can 230 ** be entered multiple times by the same thread. In such cases the, 231 ** mutex must be exited an equal number of times before another thread 232 ** can enter. If the same thread tries to enter any other kind of mutex 233 ** more than once, the behavior is undefined. 234 */ 235 static void noopMutexEnter(sqlite3_mutex *p){ 236 assert( p->id==SQLITE_MUTEX_RECURSIVE || noopMutexNotheld(p) ); 237 p->cnt++; 238 } 239 static int noopMutexTry(sqlite3_mutex *p){ 240 assert( p->id==SQLITE_MUTEX_RECURSIVE || noopMutexNotheld(p) ); 241 p->cnt++; 242 return SQLITE_OK; 243 } 244 245 /* 246 ** The sqlite3_mutex_leave() routine exits a mutex that was 247 ** previously entered by the same thread. The behavior 248 ** is undefined if the mutex is not currently entered or 249 ** is not currently allocated. SQLite will never do either. 250 */ 251 static void noopMutexLeave(sqlite3_mutex *p){ 252 assert( noopMutexHeld(p) ); 253 p->cnt--; 254 assert( p->id==SQLITE_MUTEX_RECURSIVE || noopMutexNotheld(p) ); 255 } 256 257 sqlite3_mutex_methods *sqlite3DefaultMutex(void){ 258 static sqlite3_mutex_methods sMutex = { 259 noopMutexInit, 260 noopMutexAlloc, 261 noopMutexFree, 262 noopMutexEnter, 263 noopMutexTry, 264 noopMutexLeave, 265 noopMutexEnd, 266 267 noopMutexHeld, 268 noopMutexNotheld 269 }; 270 271 return &sMutex; 272 } 273 #endif /* SQLITE_MUTEX_NOOP_DEBUG */ 274