| /* |
| ** 2007 August 28 |
| ** |
| ** The author disclaims copyright to this source code. In place of |
| ** a legal notice, here is a blessing: |
| ** |
| ** May you do good and not evil. |
| ** May you find forgiveness for yourself and forgive others. |
| ** May you share freely, never taking more than you give. |
| ** |
| ************************************************************************* |
| ** This file contains the C functions that implement mutexes for OS/2 |
| */ |
| #include "sqliteInt.h" |
| |
| /* |
| ** The code in this file is only used if SQLITE_MUTEX_OS2 is defined. |
| ** See the mutex.h file for details. |
| */ |
| #ifdef SQLITE_MUTEX_OS2 |
| |
| /********************** OS/2 Mutex Implementation ********************** |
| ** |
| ** This implementation of mutexes is built using the OS/2 API. |
| */ |
| |
| /* |
| ** The mutex object |
| ** Each recursive mutex is an instance of the following structure. |
| */ |
| struct sqlite3_mutex { |
| HMTX mutex; /* Mutex controlling the lock */ |
| int id; /* Mutex type */ |
| #ifdef SQLITE_DEBUG |
| int trace; /* True to trace changes */ |
| #endif |
| }; |
| |
| #ifdef SQLITE_DEBUG |
| #define SQLITE3_MUTEX_INITIALIZER { 0, 0, 0 } |
| #else |
| #define SQLITE3_MUTEX_INITIALIZER { 0, 0 } |
| #endif |
| |
| /* |
| ** Initialize and deinitialize the mutex subsystem. |
| */ |
| static int os2MutexInit(void){ return SQLITE_OK; } |
| static int os2MutexEnd(void){ return SQLITE_OK; } |
| |
| /* |
| ** The sqlite3_mutex_alloc() routine allocates a new |
| ** mutex and returns a pointer to it. If it returns NULL |
| ** that means that a mutex could not be allocated. |
| ** SQLite will unwind its stack and return an error. The argument |
| ** to sqlite3_mutex_alloc() is one of these integer constants: |
| ** |
| ** <ul> |
| ** <li> SQLITE_MUTEX_FAST |
| ** <li> SQLITE_MUTEX_RECURSIVE |
| ** <li> SQLITE_MUTEX_STATIC_MASTER |
| ** <li> SQLITE_MUTEX_STATIC_MEM |
| ** <li> SQLITE_MUTEX_STATIC_MEM2 |
| ** <li> SQLITE_MUTEX_STATIC_PRNG |
| ** <li> SQLITE_MUTEX_STATIC_LRU |
| ** <li> SQLITE_MUTEX_STATIC_LRU2 |
| ** </ul> |
| ** |
| ** The first two constants cause sqlite3_mutex_alloc() to create |
| ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE |
| ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. |
| ** The mutex implementation does not need to make a distinction |
| ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does |
| ** not want to. But SQLite will only request a recursive mutex in |
| ** cases where it really needs one. If a faster non-recursive mutex |
| ** implementation is available on the host platform, the mutex subsystem |
| ** might return such a mutex in response to SQLITE_MUTEX_FAST. |
| ** |
| ** The other allowed parameters to sqlite3_mutex_alloc() each return |
| ** a pointer to a static preexisting mutex. Six static mutexes are |
| ** used by the current version of SQLite. Future versions of SQLite |
| ** may add additional static mutexes. Static mutexes are for internal |
| ** use by SQLite only. Applications that use SQLite mutexes should |
| ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or |
| ** SQLITE_MUTEX_RECURSIVE. |
| ** |
| ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST |
| ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() |
| ** returns a different mutex on every call. But for the static |
| ** mutex types, the same mutex is returned on every call that has |
| ** the same type number. |
| */ |
| static sqlite3_mutex *os2MutexAlloc(int iType){ |
| sqlite3_mutex *p = NULL; |
| switch( iType ){ |
| case SQLITE_MUTEX_FAST: |
| case SQLITE_MUTEX_RECURSIVE: { |
| p = sqlite3MallocZero( sizeof(*p) ); |
| if( p ){ |
| p->id = iType; |
| if( DosCreateMutexSem( 0, &p->mutex, 0, FALSE ) != NO_ERROR ){ |
| sqlite3_free( p ); |
| p = NULL; |
| } |
| } |
| break; |
| } |
| default: { |
| static volatile int isInit = 0; |
| static sqlite3_mutex staticMutexes[6] = { |
| SQLITE3_MUTEX_INITIALIZER, |
| SQLITE3_MUTEX_INITIALIZER, |
| SQLITE3_MUTEX_INITIALIZER, |
| SQLITE3_MUTEX_INITIALIZER, |
| SQLITE3_MUTEX_INITIALIZER, |
| SQLITE3_MUTEX_INITIALIZER, |
| }; |
| if ( !isInit ){ |
| APIRET rc; |
| PTIB ptib; |
| PPIB ppib; |
| HMTX mutex; |
| char name[32]; |
| DosGetInfoBlocks( &ptib, &ppib ); |
| sqlite3_snprintf( sizeof(name), name, "\\SEM32\\SQLITE%04x", |
| ppib->pib_ulpid ); |
| while( !isInit ){ |
| mutex = 0; |
| rc = DosCreateMutexSem( name, &mutex, 0, FALSE); |
| if( rc == NO_ERROR ){ |
| unsigned int i; |
| if( !isInit ){ |
| for( i = 0; i < sizeof(staticMutexes)/sizeof(staticMutexes[0]); i++ ){ |
| DosCreateMutexSem( 0, &staticMutexes[i].mutex, 0, FALSE ); |
| } |
| isInit = 1; |
| } |
| DosCloseMutexSem( mutex ); |
| }else if( rc == ERROR_DUPLICATE_NAME ){ |
| DosSleep( 1 ); |
| }else{ |
| return p; |
| } |
| } |
| } |
| assert( iType-2 >= 0 ); |
| assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) ); |
| p = &staticMutexes[iType-2]; |
| p->id = iType; |
| break; |
| } |
| } |
| return p; |
| } |
| |
| |
| /* |
| ** This routine deallocates a previously allocated mutex. |
| ** SQLite is careful to deallocate every mutex that it allocates. |
| */ |
| static void os2MutexFree(sqlite3_mutex *p){ |
| #ifdef SQLITE_DEBUG |
| TID tid; |
| PID pid; |
| ULONG ulCount; |
| DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); |
| assert( ulCount==0 ); |
| assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); |
| #endif |
| DosCloseMutexSem( p->mutex ); |
| sqlite3_free( p ); |
| } |
| |
| #ifdef SQLITE_DEBUG |
| /* |
| ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are |
| ** intended for use inside assert() statements. |
| */ |
| static int os2MutexHeld(sqlite3_mutex *p){ |
| TID tid; |
| PID pid; |
| ULONG ulCount; |
| PTIB ptib; |
| DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); |
| if( ulCount==0 || ( ulCount>1 && p->id!=SQLITE_MUTEX_RECURSIVE ) ) |
| return 0; |
| DosGetInfoBlocks(&ptib, NULL); |
| return tid==ptib->tib_ptib2->tib2_ultid; |
| } |
| static int os2MutexNotheld(sqlite3_mutex *p){ |
| TID tid; |
| PID pid; |
| ULONG ulCount; |
| PTIB ptib; |
| DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); |
| if( ulCount==0 ) |
| return 1; |
| DosGetInfoBlocks(&ptib, NULL); |
| return tid!=ptib->tib_ptib2->tib2_ultid; |
| } |
| static void os2MutexTrace(sqlite3_mutex *p, char *pAction){ |
| TID tid; |
| PID pid; |
| ULONG ulCount; |
| DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount); |
| printf("%s mutex %p (%d) with nRef=%ld\n", pAction, (void*)p, p->trace, ulCount); |
| } |
| #endif |
| |
| /* |
| ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt |
| ** to enter a mutex. If another thread is already within the mutex, |
| ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return |
| ** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK |
| ** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can |
| ** be entered multiple times by the same thread. In such cases the, |
| ** mutex must be exited an equal number of times before another thread |
| ** can enter. If the same thread tries to enter any other kind of mutex |
| ** more than once, the behavior is undefined. |
| */ |
| static void os2MutexEnter(sqlite3_mutex *p){ |
| assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) ); |
| DosRequestMutexSem(p->mutex, SEM_INDEFINITE_WAIT); |
| #ifdef SQLITE_DEBUG |
| if( p->trace ) os2MutexTrace(p, "enter"); |
| #endif |
| } |
| static int os2MutexTry(sqlite3_mutex *p){ |
| int rc = SQLITE_BUSY; |
| assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) ); |
| if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR ) { |
| rc = SQLITE_OK; |
| #ifdef SQLITE_DEBUG |
| if( p->trace ) os2MutexTrace(p, "try"); |
| #endif |
| } |
| return rc; |
| } |
| |
| /* |
| ** The sqlite3_mutex_leave() routine exits a mutex that was |
| ** previously entered by the same thread. The behavior |
| ** is undefined if the mutex is not currently entered or |
| ** is not currently allocated. SQLite will never do either. |
| */ |
| static void os2MutexLeave(sqlite3_mutex *p){ |
| assert( os2MutexHeld(p) ); |
| DosReleaseMutexSem(p->mutex); |
| #ifdef SQLITE_DEBUG |
| if( p->trace ) os2MutexTrace(p, "leave"); |
| #endif |
| } |
| |
| sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ |
| static const sqlite3_mutex_methods sMutex = { |
| os2MutexInit, |
| os2MutexEnd, |
| os2MutexAlloc, |
| os2MutexFree, |
| os2MutexEnter, |
| os2MutexTry, |
| os2MutexLeave, |
| #ifdef SQLITE_DEBUG |
| os2MutexHeld, |
| os2MutexNotheld |
| #else |
| 0, |
| 0 |
| #endif |
| }; |
| |
| return &sMutex; |
| } |
| #endif /* SQLITE_MUTEX_OS2 */ |