OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ** 2007 August 28 |
| 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 for OS/2 |
| 13 */ |
| 14 #include "sqliteInt.h" |
| 15 |
| 16 /* |
| 17 ** The code in this file is only used if SQLITE_MUTEX_OS2 is defined. |
| 18 ** See the mutex.h file for details. |
| 19 */ |
| 20 #ifdef SQLITE_MUTEX_OS2 |
| 21 |
| 22 /********************** OS/2 Mutex Implementation ********************** |
| 23 ** |
| 24 ** This implementation of mutexes is built using the OS/2 API. |
| 25 */ |
| 26 |
| 27 /* |
| 28 ** The mutex object |
| 29 ** Each recursive mutex is an instance of the following structure. |
| 30 */ |
| 31 struct sqlite3_mutex { |
| 32 HMTX mutex; /* Mutex controlling the lock */ |
| 33 int id; /* Mutex type */ |
| 34 #ifdef SQLITE_DEBUG |
| 35 int trace; /* True to trace changes */ |
| 36 #endif |
| 37 }; |
| 38 |
| 39 #ifdef SQLITE_DEBUG |
| 40 #define SQLITE3_MUTEX_INITIALIZER { 0, 0, 0 } |
| 41 #else |
| 42 #define SQLITE3_MUTEX_INITIALIZER { 0, 0 } |
| 43 #endif |
| 44 |
| 45 /* |
| 46 ** Initialize and deinitialize the mutex subsystem. |
| 47 */ |
| 48 static int os2MutexInit(void){ return SQLITE_OK; } |
| 49 static int os2MutexEnd(void){ return SQLITE_OK; } |
| 50 |
| 51 /* |
| 52 ** The sqlite3_mutex_alloc() routine allocates a new |
| 53 ** mutex and returns a pointer to it. If it returns NULL |
| 54 ** that means that a mutex could not be allocated. |
| 55 ** SQLite will unwind its stack and return an error. The argument |
| 56 ** to sqlite3_mutex_alloc() is one of these integer constants: |
| 57 ** |
| 58 ** <ul> |
| 59 ** <li> SQLITE_MUTEX_FAST |
| 60 ** <li> SQLITE_MUTEX_RECURSIVE |
| 61 ** <li> SQLITE_MUTEX_STATIC_MASTER |
| 62 ** <li> SQLITE_MUTEX_STATIC_MEM |
| 63 ** <li> SQLITE_MUTEX_STATIC_MEM2 |
| 64 ** <li> SQLITE_MUTEX_STATIC_PRNG |
| 65 ** <li> SQLITE_MUTEX_STATIC_LRU |
| 66 ** <li> SQLITE_MUTEX_STATIC_LRU2 |
| 67 ** </ul> |
| 68 ** |
| 69 ** The first two constants cause sqlite3_mutex_alloc() to create |
| 70 ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE |
| 71 ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. |
| 72 ** The mutex implementation does not need to make a distinction |
| 73 ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does |
| 74 ** not want to. But SQLite will only request a recursive mutex in |
| 75 ** cases where it really needs one. If a faster non-recursive mutex |
| 76 ** implementation is available on the host platform, the mutex subsystem |
| 77 ** might return such a mutex in response to SQLITE_MUTEX_FAST. |
| 78 ** |
| 79 ** The other allowed parameters to sqlite3_mutex_alloc() each return |
| 80 ** a pointer to a static preexisting mutex. Six static mutexes are |
| 81 ** used by the current version of SQLite. Future versions of SQLite |
| 82 ** may add additional static mutexes. Static mutexes are for internal |
| 83 ** use by SQLite only. Applications that use SQLite mutexes should |
| 84 ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or |
| 85 ** SQLITE_MUTEX_RECURSIVE. |
| 86 ** |
| 87 ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST |
| 88 ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() |
| 89 ** returns a different mutex on every call. But for the static |
| 90 ** mutex types, the same mutex is returned on every call that has |
| 91 ** the same type number. |
| 92 */ |
| 93 static sqlite3_mutex *os2MutexAlloc(int iType){ |
| 94 sqlite3_mutex *p = NULL; |
| 95 switch( iType ){ |
| 96 case SQLITE_MUTEX_FAST: |
| 97 case SQLITE_MUTEX_RECURSIVE: { |
| 98 p = sqlite3MallocZero( sizeof(*p) ); |
| 99 if( p ){ |
| 100 p->id = iType; |
| 101 if( DosCreateMutexSem( 0, &p->mutex, 0, FALSE ) != NO_ERROR ){ |
| 102 sqlite3_free( p ); |
| 103 p = NULL; |
| 104 } |
| 105 } |
| 106 break; |
| 107 } |
| 108 default: { |
| 109 static volatile int isInit = 0; |
| 110 static sqlite3_mutex staticMutexes[6] = { |
| 111 SQLITE3_MUTEX_INITIALIZER, |
| 112 SQLITE3_MUTEX_INITIALIZER, |
| 113 SQLITE3_MUTEX_INITIALIZER, |
| 114 SQLITE3_MUTEX_INITIALIZER, |
| 115 SQLITE3_MUTEX_INITIALIZER, |
| 116 SQLITE3_MUTEX_INITIALIZER, |
| 117 }; |
| 118 if ( !isInit ){ |
| 119 APIRET rc; |
| 120 PTIB ptib; |
| 121 PPIB ppib; |
| 122 HMTX mutex; |
| 123 char name[32]; |
| 124 DosGetInfoBlocks( &ptib, &ppib ); |
| 125 sqlite3_snprintf( sizeof(name), name, "\\SEM32\\SQLITE%04x", |
| 126 ppib->pib_ulpid ); |
| 127 while( !isInit ){ |
| 128 mutex = 0; |
| 129 rc = DosCreateMutexSem( name, &mutex, 0, FALSE); |
| 130 if( rc == NO_ERROR ){ |
| 131 unsigned int i; |
| 132 if( !isInit ){ |
| 133 for( i = 0; i < sizeof(staticMutexes)/sizeof(staticMutexes[0]); i+
+ ){ |
| 134 DosCreateMutexSem( 0, &staticMutexes[i].mutex, 0, FALSE ); |
| 135 } |
| 136 isInit = 1; |
| 137 } |
| 138 DosCloseMutexSem( mutex ); |
| 139 }else if( rc == ERROR_DUPLICATE_NAME ){ |
| 140 DosSleep( 1 ); |
| 141 }else{ |
| 142 return p; |
| 143 } |
| 144 } |
| 145 } |
| 146 assert( iType-2 >= 0 ); |
| 147 assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) ); |
| 148 p = &staticMutexes[iType-2]; |
| 149 p->id = iType; |
| 150 break; |
| 151 } |
| 152 } |
| 153 return p; |
| 154 } |
| 155 |
| 156 |
| 157 /* |
| 158 ** This routine deallocates a previously allocated mutex. |
| 159 ** SQLite is careful to deallocate every mutex that it allocates. |
| 160 */ |
| 161 static void os2MutexFree(sqlite3_mutex *p){ |
| 162 #ifdef SQLITE_DEBUG |
| 163 TID tid; |
| 164 PID pid; |
| 165 ULONG ulCount; |
| 166 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); |
| 167 assert( ulCount==0 ); |
| 168 assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); |
| 169 #endif |
| 170 DosCloseMutexSem( p->mutex ); |
| 171 sqlite3_free( p ); |
| 172 } |
| 173 |
| 174 #ifdef SQLITE_DEBUG |
| 175 /* |
| 176 ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are |
| 177 ** intended for use inside assert() statements. |
| 178 */ |
| 179 static int os2MutexHeld(sqlite3_mutex *p){ |
| 180 TID tid; |
| 181 PID pid; |
| 182 ULONG ulCount; |
| 183 PTIB ptib; |
| 184 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); |
| 185 if( ulCount==0 || ( ulCount>1 && p->id!=SQLITE_MUTEX_RECURSIVE ) ) |
| 186 return 0; |
| 187 DosGetInfoBlocks(&ptib, NULL); |
| 188 return tid==ptib->tib_ptib2->tib2_ultid; |
| 189 } |
| 190 static int os2MutexNotheld(sqlite3_mutex *p){ |
| 191 TID tid; |
| 192 PID pid; |
| 193 ULONG ulCount; |
| 194 PTIB ptib; |
| 195 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); |
| 196 if( ulCount==0 ) |
| 197 return 1; |
| 198 DosGetInfoBlocks(&ptib, NULL); |
| 199 return tid!=ptib->tib_ptib2->tib2_ultid; |
| 200 } |
| 201 static void os2MutexTrace(sqlite3_mutex *p, char *pAction){ |
| 202 TID tid; |
| 203 PID pid; |
| 204 ULONG ulCount; |
| 205 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); |
| 206 printf("%s mutex %p (%d) with nRef=%ld\n", pAction, (void*)p, p->trace, ulCoun
t); |
| 207 } |
| 208 #endif |
| 209 |
| 210 /* |
| 211 ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt |
| 212 ** to enter a mutex. If another thread is already within the mutex, |
| 213 ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return |
| 214 ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK |
| 215 ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can |
| 216 ** be entered multiple times by the same thread. In such cases the, |
| 217 ** mutex must be exited an equal number of times before another thread |
| 218 ** can enter. If the same thread tries to enter any other kind of mutex |
| 219 ** more than once, the behavior is undefined. |
| 220 */ |
| 221 static void os2MutexEnter(sqlite3_mutex *p){ |
| 222 assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) ); |
| 223 DosRequestMutexSem(p->mutex, SEM_INDEFINITE_WAIT); |
| 224 #ifdef SQLITE_DEBUG |
| 225 if( p->trace ) os2MutexTrace(p, "enter"); |
| 226 #endif |
| 227 } |
| 228 static int os2MutexTry(sqlite3_mutex *p){ |
| 229 int rc = SQLITE_BUSY; |
| 230 assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) ); |
| 231 if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR ) { |
| 232 rc = SQLITE_OK; |
| 233 #ifdef SQLITE_DEBUG |
| 234 if( p->trace ) os2MutexTrace(p, "try"); |
| 235 #endif |
| 236 } |
| 237 return rc; |
| 238 } |
| 239 |
| 240 /* |
| 241 ** The sqlite3_mutex_leave() routine exits a mutex that was |
| 242 ** previously entered by the same thread. The behavior |
| 243 ** is undefined if the mutex is not currently entered or |
| 244 ** is not currently allocated. SQLite will never do either. |
| 245 */ |
| 246 static void os2MutexLeave(sqlite3_mutex *p){ |
| 247 assert( os2MutexHeld(p) ); |
| 248 DosReleaseMutexSem(p->mutex); |
| 249 #ifdef SQLITE_DEBUG |
| 250 if( p->trace ) os2MutexTrace(p, "leave"); |
| 251 #endif |
| 252 } |
| 253 |
| 254 sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ |
| 255 static const sqlite3_mutex_methods sMutex = { |
| 256 os2MutexInit, |
| 257 os2MutexEnd, |
| 258 os2MutexAlloc, |
| 259 os2MutexFree, |
| 260 os2MutexEnter, |
| 261 os2MutexTry, |
| 262 os2MutexLeave, |
| 263 #ifdef SQLITE_DEBUG |
| 264 os2MutexHeld, |
| 265 os2MutexNotheld |
| 266 #else |
| 267 0, |
| 268 0 |
| 269 #endif |
| 270 }; |
| 271 |
| 272 return &sMutex; |
| 273 } |
| 274 #endif /* SQLITE_MUTEX_OS2 */ |
OLD | NEW |