• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
os2MutexInit(void)48 static int os2MutexInit(void){ return SQLITE_OK; }
os2MutexEnd(void)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 */
os2MutexAlloc(int iType)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 */
os2MutexFree(sqlite3_mutex * p)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 */
os2MutexHeld(sqlite3_mutex * p)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 }
os2MutexNotheld(sqlite3_mutex * p)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 }
os2MutexTrace(sqlite3_mutex * p,char * pAction)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, 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 */
os2MutexEnter(sqlite3_mutex * p)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 }
os2MutexTry(sqlite3_mutex * p)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 */
os2MutexLeave(sqlite3_mutex * p)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 
sqlite3DefaultMutex(void)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 */
275