blob: f16dc218d91972b70317267f932a5c934f7e22ef [file] [log] [blame]
drh437b9012007-08-28 16:34:42 +00001/*
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
drh437b9012007-08-28 16:34:42 +000013*/
14#include "sqliteInt.h"
15
drh437b9012007-08-28 16:34:42 +000016/*
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
pweilbacherec70b6b2007-09-20 21:40:23 +000022/********************** OS/2 Mutex Implementation **********************
23**
24** This implementation of mutexes is built using the OS/2 API.
25*/
drh437b9012007-08-28 16:34:42 +000026
27/*
28** The mutex object
pweilbacherec70b6b2007-09-20 21:40:23 +000029** Each recursive mutex is an instance of the following structure.
drh437b9012007-08-28 16:34:42 +000030*/
31struct sqlite3_mutex {
pweilbacherec70b6b2007-09-20 21:40:23 +000032 HMTX mutex; /* Mutex controlling the lock */
33 int id; /* Mutex type */
34 int nRef; /* Number of references */
35 TID owner; /* Thread holding this mutex */
drh437b9012007-08-28 16:34:42 +000036};
37
pweilbacherdc965c32008-02-01 19:42:37 +000038#define OS2_MUTEX_INITIALIZER 0,0,0,0
39
drh437b9012007-08-28 16:34:42 +000040/*
drh40257ff2008-06-13 18:24:27 +000041** Initialize and deinitialize the mutex subsystem.
42*/
pweilbacher26169642008-06-23 22:13:27 +000043static int os2MutexInit(void){ return SQLITE_OK; }
44static int os2MutexEnd(void){ return SQLITE_OK; }
drh40257ff2008-06-13 18:24:27 +000045
46/*
drh437b9012007-08-28 16:34:42 +000047** The sqlite3_mutex_alloc() routine allocates a new
48** mutex and returns a pointer to it. If it returns NULL
49** that means that a mutex could not be allocated.
pweilbacherec70b6b2007-09-20 21:40:23 +000050** SQLite will unwind its stack and return an error. The argument
51** to sqlite3_mutex_alloc() is one of these integer constants:
52**
53** <ul>
54** <li> SQLITE_MUTEX_FAST 0
55** <li> SQLITE_MUTEX_RECURSIVE 1
56** <li> SQLITE_MUTEX_STATIC_MASTER 2
57** <li> SQLITE_MUTEX_STATIC_MEM 3
58** <li> SQLITE_MUTEX_STATIC_PRNG 4
59** </ul>
60**
61** The first two constants cause sqlite3_mutex_alloc() to create
62** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
63** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
64** The mutex implementation does not need to make a distinction
65** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
66** not want to. But SQLite will only request a recursive mutex in
67** cases where it really needs one. If a faster non-recursive mutex
68** implementation is available on the host platform, the mutex subsystem
69** might return such a mutex in response to SQLITE_MUTEX_FAST.
70**
71** The other allowed parameters to sqlite3_mutex_alloc() each return
72** a pointer to a static preexisting mutex. Three static mutexes are
73** used by the current version of SQLite. Future versions of SQLite
74** may add additional static mutexes. Static mutexes are for internal
75** use by SQLite only. Applications that use SQLite mutexes should
76** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
77** SQLITE_MUTEX_RECURSIVE.
78**
79** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
80** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
81** returns a different mutex on every call. But for the static
82** mutex types, the same mutex is returned on every call that has
83** the same type number.
drh437b9012007-08-28 16:34:42 +000084*/
pweilbacher26169642008-06-23 22:13:27 +000085static sqlite3_mutex *os2MutexAlloc(int iType){
pweilbacherdc965c32008-02-01 19:42:37 +000086 sqlite3_mutex *p = NULL;
pweilbacherec70b6b2007-09-20 21:40:23 +000087 switch( iType ){
drh437b9012007-08-28 16:34:42 +000088 case SQLITE_MUTEX_FAST:
89 case SQLITE_MUTEX_RECURSIVE: {
pweilbacherec70b6b2007-09-20 21:40:23 +000090 p = sqlite3MallocZero( sizeof(*p) );
91 if( p ){
pweilbacherec70b6b2007-09-20 21:40:23 +000092 p->id = iType;
pweilbacherdc965c32008-02-01 19:42:37 +000093 if( DosCreateMutexSem( 0, &p->mutex, 0, FALSE ) != NO_ERROR ){
94 sqlite3_free( p );
95 p = NULL;
96 }
drh437b9012007-08-28 16:34:42 +000097 }
98 break;
99 }
100 default: {
pweilbacherdc965c32008-02-01 19:42:37 +0000101 static volatile int isInit = 0;
102 static sqlite3_mutex staticMutexes[] = {
103 { OS2_MUTEX_INITIALIZER, },
104 { OS2_MUTEX_INITIALIZER, },
105 { OS2_MUTEX_INITIALIZER, },
106 { OS2_MUTEX_INITIALIZER, },
107 { OS2_MUTEX_INITIALIZER, },
danielk1977dfb316d2008-03-26 18:34:43 +0000108 { OS2_MUTEX_INITIALIZER, },
pweilbacherdc965c32008-02-01 19:42:37 +0000109 };
110 if ( !isInit ){
111 APIRET rc;
112 PTIB ptib;
113 PPIB ppib;
114 HMTX mutex;
115 char name[32];
116 DosGetInfoBlocks( &ptib, &ppib );
117 sqlite3_snprintf( sizeof(name), name, "\\SEM32\\SQLITE%04x",
118 ppib->pib_ulpid );
119 while( !isInit ){
120 mutex = 0;
121 rc = DosCreateMutexSem( name, &mutex, 0, FALSE);
122 if( rc == NO_ERROR ){
pweilbacherc06b54f2008-11-22 19:50:53 +0000123 unsigned int i;
pweilbacherdc965c32008-02-01 19:42:37 +0000124 if( !isInit ){
125 for( i = 0; i < sizeof(staticMutexes)/sizeof(staticMutexes[0]); i++ ){
126 DosCreateMutexSem( 0, &staticMutexes[i].mutex, 0, FALSE );
127 }
128 isInit = 1;
129 }
130 DosCloseMutexSem( mutex );
131 }else if( rc == ERROR_DUPLICATE_NAME ){
132 DosSleep( 1 );
133 }else{
134 return p;
pweilbacherec70b6b2007-09-20 21:40:23 +0000135 }
pweilbacherec70b6b2007-09-20 21:40:23 +0000136 }
137 }
138 assert( iType-2 >= 0 );
139 assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) );
140 p = &staticMutexes[iType-2];
141 p->id = iType;
drh437b9012007-08-28 16:34:42 +0000142 break;
143 }
144 }
pweilbacherec70b6b2007-09-20 21:40:23 +0000145 return p;
drh437b9012007-08-28 16:34:42 +0000146}
147
pweilbacherec70b6b2007-09-20 21:40:23 +0000148
drh437b9012007-08-28 16:34:42 +0000149/*
150** This routine deallocates a previously allocated mutex.
pweilbacherec70b6b2007-09-20 21:40:23 +0000151** SQLite is careful to deallocate every mutex that it allocates.
drh437b9012007-08-28 16:34:42 +0000152*/
pweilbacher26169642008-06-23 22:13:27 +0000153static void os2MutexFree(sqlite3_mutex *p){
drh40257ff2008-06-13 18:24:27 +0000154 if( p==0 ) return;
pweilbacherec70b6b2007-09-20 21:40:23 +0000155 assert( p->nRef==0 );
drh437b9012007-08-28 16:34:42 +0000156 assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
pweilbacherdc965c32008-02-01 19:42:37 +0000157 DosCloseMutexSem( p->mutex );
158 sqlite3_free( p );
drh437b9012007-08-28 16:34:42 +0000159}
160
drhcfa35662009-12-01 14:31:18 +0000161#ifdef SQLITE_DEBUG
162/*
163** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
164** intended for use inside assert() statements.
165*/
166static int os2MutexHeld(sqlite3_mutex *p){
167 TID tid;
168 PID pid;
169 ULONG ulCount;
170 PTIB ptib;
171 if( p!=0 ) {
172 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
173 } else {
174 DosGetInfoBlocks(&ptib, NULL);
175 tid = ptib->tib_ptib2->tib2_ultid;
176 }
177 return p==0 || (p->nRef!=0 && p->owner==tid);
178}
179static int os2MutexNotheld(sqlite3_mutex *p){
180 TID tid;
181 PID pid;
182 ULONG ulCount;
183 PTIB ptib;
184 if( p!= 0 ) {
185 DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
186 } else {
187 DosGetInfoBlocks(&ptib, NULL);
188 tid = ptib->tib_ptib2->tib2_ultid;
189 }
190 return p==0 || p->nRef==0 || p->owner!=tid;
191}
192#endif
193
drh437b9012007-08-28 16:34:42 +0000194/*
195** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
196** to enter a mutex. If another thread is already within the mutex,
197** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
198** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
199** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
200** be entered multiple times by the same thread. In such cases the,
201** mutex must be exited an equal number of times before another thread
202** can enter. If the same thread tries to enter any other kind of mutex
203** more than once, the behavior is undefined.
204*/
pweilbacher26169642008-06-23 22:13:27 +0000205static void os2MutexEnter(sqlite3_mutex *p){
pweilbacherec70b6b2007-09-20 21:40:23 +0000206 TID tid;
207 PID holder1;
208 ULONG holder2;
drh40257ff2008-06-13 18:24:27 +0000209 if( p==0 ) return;
pweilbacher26169642008-06-23 22:13:27 +0000210 assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
pweilbacherec70b6b2007-09-20 21:40:23 +0000211 DosRequestMutexSem(p->mutex, SEM_INDEFINITE_WAIT);
212 DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
213 p->owner = tid;
214 p->nRef++;
drh437b9012007-08-28 16:34:42 +0000215}
pweilbacher26169642008-06-23 22:13:27 +0000216static int os2MutexTry(sqlite3_mutex *p){
pweilbacherec70b6b2007-09-20 21:40:23 +0000217 int rc;
218 TID tid;
219 PID holder1;
220 ULONG holder2;
drh40257ff2008-06-13 18:24:27 +0000221 if( p==0 ) return SQLITE_OK;
pweilbacher26169642008-06-23 22:13:27 +0000222 assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
pweilbacherec70b6b2007-09-20 21:40:23 +0000223 if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR) {
224 DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
225 p->owner = tid;
226 p->nRef++;
227 rc = SQLITE_OK;
228 } else {
229 rc = SQLITE_BUSY;
230 }
231
232 return rc;
drh437b9012007-08-28 16:34:42 +0000233}
234
235/*
236** The sqlite3_mutex_leave() routine exits a mutex that was
237** previously entered by the same thread. The behavior
238** is undefined if the mutex is not currently entered or
239** is not currently allocated. SQLite will never do either.
240*/
pweilbacher26169642008-06-23 22:13:27 +0000241static void os2MutexLeave(sqlite3_mutex *p){
pweilbacherec70b6b2007-09-20 21:40:23 +0000242 TID tid;
243 PID holder1;
244 ULONG holder2;
drh40257ff2008-06-13 18:24:27 +0000245 if( p==0 ) return;
pweilbacherec70b6b2007-09-20 21:40:23 +0000246 assert( p->nRef>0 );
247 DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
248 assert( p->owner==tid );
249 p->nRef--;
250 assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
251 DosReleaseMutexSem(p->mutex);
drh437b9012007-08-28 16:34:42 +0000252}
253
pweilbacher6a9773e2008-06-18 21:08:16 +0000254sqlite3_mutex_methods *sqlite3DefaultMutex(void){
255 static sqlite3_mutex_methods sMutex = {
256 os2MutexInit,
danielk19774a9d1f62008-06-19 08:51:23 +0000257 os2MutexEnd,
pweilbacher6a9773e2008-06-18 21:08:16 +0000258 os2MutexAlloc,
259 os2MutexFree,
260 os2MutexEnter,
261 os2MutexTry,
262 os2MutexLeave,
pweilbacher26169642008-06-23 22:13:27 +0000263#ifdef SQLITE_DEBUG
pweilbacher6a9773e2008-06-18 21:08:16 +0000264 os2MutexHeld,
265 os2MutexNotheld
pweilbacher26169642008-06-23 22:13:27 +0000266#endif
pweilbacher6a9773e2008-06-18 21:08:16 +0000267 };
268
269 return &sMutex;
270}
drh437b9012007-08-28 16:34:42 +0000271#endif /* SQLITE_MUTEX_OS2 */