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*/ 31struct 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*/ 48static int os2MutexInit(void){ return SQLITE_OK; } 49static 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*/ 93static 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*/ 161static 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*/ 179static 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} 190static 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} 201static 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, ulCount); 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*/ 221static 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} 228static 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*/ 246static 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 254sqlite3_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 */ 275