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