xref: /sqlite-3.40.0/src/test_mutex.c (revision 19dd29fc)
1 /*
2 ** 2008 June 18
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 **
13 ** $Id: test_mutex.c,v 1.9 2008/07/10 20:41:50 drh Exp $
14 */
15 
16 #include "tcl.h"
17 #include "sqlite3.h"
18 #include <stdlib.h>
19 #include <assert.h>
20 #include <string.h>
21 
22 /* defined in test1.c */
23 const char *sqlite3TestErrorName(int);
24 
25 /* A countable mutex */
26 struct sqlite3_mutex {
27   sqlite3_mutex *pReal;
28   int eType;
29 };
30 
31 /* State variables */
32 static struct test_mutex_globals {
33   int isInstalled;              /* True if installed */
34   int disableInit;              /* True to cause sqlite3_initalize() to fail */
35   int disableTry;               /* True to force sqlite3_mutex_try() to fail */
36   int isInit;                   /* True if initialized */
37   sqlite3_mutex_methods m;      /* Interface to "real" mutex system */
38   int aCounter[8];              /* Number of grabs of each type of mutex */
39   sqlite3_mutex aStatic[6];     /* The six static mutexes */
40 } g;
41 
42 /* Return true if the countable mutex is currently held */
43 static int counterMutexHeld(sqlite3_mutex *p){
44   return g.m.xMutexHeld(p->pReal);
45 }
46 
47 /* Return true if the countable mutex is not currently held */
48 static int counterMutexNotheld(sqlite3_mutex *p){
49   return g.m.xMutexNotheld(p->pReal);
50 }
51 
52 /* Initialize the countable mutex interface
53 ** Or, if g.disableInit is non-zero, then do not initialize but instead
54 ** return the value of g.disableInit as the result code.  This can be used
55 ** to simulate an initialization failure.
56 */
57 static int counterMutexInit(void){
58   int rc;
59   if( g.disableInit ) return g.disableInit;
60   rc = g.m.xMutexInit();
61   g.isInit = 1;
62   return rc;
63 }
64 
65 /*
66 ** Uninitialize the mutex subsystem
67 */
68 static int counterMutexEnd(void){
69   g.isInit = 0;
70   return g.m.xMutexEnd();
71 }
72 
73 /*
74 ** Allocate a countable mutex
75 */
76 static sqlite3_mutex *counterMutexAlloc(int eType){
77   sqlite3_mutex *pReal;
78   sqlite3_mutex *pRet = 0;
79 
80   assert( g.isInit );
81   assert(eType<8 && eType>=0);
82 
83   pReal = g.m.xMutexAlloc(eType);
84   if( !pReal ) return 0;
85 
86   if( eType==SQLITE_MUTEX_FAST || eType==SQLITE_MUTEX_RECURSIVE ){
87     pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex));
88   }else{
89     pRet = &g.aStatic[eType-2];
90   }
91 
92   pRet->eType = eType;
93   pRet->pReal = pReal;
94   return pRet;
95 }
96 
97 /*
98 ** Free a countable mutex
99 */
100 static void counterMutexFree(sqlite3_mutex *p){
101   assert( g.isInit );
102   g.m.xMutexFree(p->pReal);
103   if( p->eType==SQLITE_MUTEX_FAST || p->eType==SQLITE_MUTEX_RECURSIVE ){
104     free(p);
105   }
106 }
107 
108 /*
109 ** Enter a countable mutex.  Block until entry is safe.
110 */
111 static void counterMutexEnter(sqlite3_mutex *p){
112   assert( g.isInit );
113   g.aCounter[p->eType]++;
114   g.m.xMutexEnter(p->pReal);
115 }
116 
117 /*
118 ** Try to enter a mutex.  Return true on success.
119 */
120 static int counterMutexTry(sqlite3_mutex *p){
121   assert( g.isInit );
122   g.aCounter[p->eType]++;
123   if( g.disableTry ) return SQLITE_BUSY;
124   return g.m.xMutexTry(p->pReal);
125 }
126 
127 /* Leave a mutex
128 */
129 static void counterMutexLeave(sqlite3_mutex *p){
130   assert( g.isInit );
131   g.m.xMutexLeave(p->pReal);
132 }
133 
134 /*
135 ** sqlite3_shutdown
136 */
137 static int test_shutdown(
138   void * clientData,
139   Tcl_Interp *interp,
140   int objc,
141   Tcl_Obj *CONST objv[]
142 ){
143   int rc;
144 
145   if( objc!=1 ){
146     Tcl_WrongNumArgs(interp, 1, objv, "");
147     return TCL_ERROR;
148   }
149 
150   rc = sqlite3_shutdown();
151   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
152   return TCL_OK;
153 }
154 
155 /*
156 ** sqlite3_initialize
157 */
158 static int test_initialize(
159   void * clientData,
160   Tcl_Interp *interp,
161   int objc,
162   Tcl_Obj *CONST objv[]
163 ){
164   int rc;
165 
166   if( objc!=1 ){
167     Tcl_WrongNumArgs(interp, 1, objv, "");
168     return TCL_ERROR;
169   }
170 
171   rc = sqlite3_initialize();
172   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
173   return TCL_OK;
174 }
175 
176 /*
177 ** install_mutex_counters BOOLEAN
178 */
179 static int test_install_mutex_counters(
180   void * clientData,
181   Tcl_Interp *interp,
182   int objc,
183   Tcl_Obj *CONST objv[]
184 ){
185   int rc = SQLITE_OK;
186   int isInstall;
187 
188   sqlite3_mutex_methods counter_methods = {
189     counterMutexInit,
190     counterMutexEnd,
191     counterMutexAlloc,
192     counterMutexFree,
193     counterMutexEnter,
194     counterMutexTry,
195     counterMutexLeave,
196     counterMutexHeld,
197     counterMutexNotheld
198   };
199 
200   if( objc!=2 ){
201     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
202     return TCL_ERROR;
203   }
204   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
205     return TCL_ERROR;
206   }
207 
208   assert(isInstall==0 || isInstall==1);
209   assert(g.isInstalled==0 || g.isInstalled==1);
210   if( isInstall==g.isInstalled ){
211     Tcl_AppendResult(interp, "mutex counters are ", 0);
212     Tcl_AppendResult(interp, isInstall?"already installed":"not installed", 0);
213     return TCL_ERROR;
214   }
215 
216   if( isInstall ){
217     assert( g.m.xMutexAlloc==0 );
218     rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m);
219     if( rc==SQLITE_OK ){
220       sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods);
221     }
222     g.disableTry = 0;
223   }else{
224     assert( g.m.xMutexAlloc );
225     rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m);
226     memset(&g.m, 0, sizeof(sqlite3_mutex_methods));
227   }
228 
229   if( rc==SQLITE_OK ){
230     g.isInstalled = isInstall;
231   }
232 
233   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
234   return TCL_OK;
235 }
236 
237 /*
238 ** read_mutex_counters
239 */
240 static int test_read_mutex_counters(
241   void * clientData,
242   Tcl_Interp *interp,
243   int objc,
244   Tcl_Obj *CONST objv[]
245 ){
246   Tcl_Obj *pRet;
247   int ii;
248   char *aName[8] = {
249     "fast",        "recursive",   "static_master", "static_mem",
250     "static_mem2", "static_prng", "static_lru",    "static_lru2"
251   };
252 
253   if( objc!=1 ){
254     Tcl_WrongNumArgs(interp, 1, objv, "");
255     return TCL_ERROR;
256   }
257 
258   pRet = Tcl_NewObj();
259   Tcl_IncrRefCount(pRet);
260   for(ii=0; ii<8; ii++){
261     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1));
262     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii]));
263   }
264   Tcl_SetObjResult(interp, pRet);
265   Tcl_DecrRefCount(pRet);
266 
267   return TCL_OK;
268 }
269 
270 /*
271 ** clear_mutex_counters
272 */
273 static int test_clear_mutex_counters(
274   void * clientData,
275   Tcl_Interp *interp,
276   int objc,
277   Tcl_Obj *CONST objv[]
278 ){
279   int ii;
280 
281   if( objc!=1 ){
282     Tcl_WrongNumArgs(interp, 1, objv, "");
283     return TCL_ERROR;
284   }
285 
286   for(ii=0; ii<8; ii++){
287     g.aCounter[ii] = 0;
288   }
289   return TCL_OK;
290 }
291 
292 /*
293 ** Create and free a mutex.  Return the mutex pointer.  The pointer
294 ** will be invalid since the mutex has already been freed.  The
295 ** return pointer just checks to see if the mutex really was allocated.
296 */
297 static int test_alloc_mutex(
298   void * clientData,
299   Tcl_Interp *interp,
300   int objc,
301   Tcl_Obj *CONST objv[]
302 ){
303   sqlite3_mutex *p = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
304   char zBuf[100];
305   sqlite3_mutex_free(p);
306   sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p);
307   Tcl_AppendResult(interp, zBuf, (char*)0);
308   return TCL_OK;
309 }
310 
311 /*
312 ** sqlite3_config OPTION
313 **
314 ** OPTION can be either one of the keywords:
315 **
316 **            SQLITE_CONFIG_SINGLETHREAD
317 **            SQLITE_CONFIG_MULTITHREAD
318 **            SQLITE_CONFIG_SERIALIZED
319 **
320 ** Or OPTION can be an raw integer.
321 */
322 static int test_config(
323   void * clientData,
324   Tcl_Interp *interp,
325   int objc,
326   Tcl_Obj *CONST objv[]
327 ){
328   struct ConfigOption {
329     const char *zName;
330     int iValue;
331   } aOpt[] = {
332     {"singlethread", SQLITE_CONFIG_SINGLETHREAD},
333     {"multithread",  SQLITE_CONFIG_MULTITHREAD},
334     {"serialized",   SQLITE_CONFIG_SERIALIZED},
335     {0, 0}
336   };
337   int s = sizeof(struct ConfigOption);
338   int i;
339   int rc;
340 
341   if( objc!=2 ){
342     Tcl_WrongNumArgs(interp, 1, objv, "");
343     return TCL_ERROR;
344   }
345 
346   if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){
347     if( Tcl_GetIntFromObj(interp, objv[1], &i) ){
348       return TCL_ERROR;
349     }
350   }else{
351     i = aOpt[i].iValue;
352   }
353 
354   rc = sqlite3_config(i);
355   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
356   return TCL_OK;
357 }
358 
359 int Sqlitetest_mutex_Init(Tcl_Interp *interp){
360   static struct {
361     char *zName;
362     Tcl_ObjCmdProc *xProc;
363   } aCmd[] = {
364     { "sqlite3_shutdown",        (Tcl_ObjCmdProc*)test_shutdown },
365     { "sqlite3_initialize",      (Tcl_ObjCmdProc*)test_initialize },
366     { "sqlite3_config",          (Tcl_ObjCmdProc*)test_config },
367 
368     { "alloc_dealloc_mutex",     (Tcl_ObjCmdProc*)test_alloc_mutex },
369     { "install_mutex_counters",  (Tcl_ObjCmdProc*)test_install_mutex_counters },
370     { "read_mutex_counters",     (Tcl_ObjCmdProc*)test_read_mutex_counters },
371     { "clear_mutex_counters",    (Tcl_ObjCmdProc*)test_clear_mutex_counters },
372   };
373   int i;
374   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
375     Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
376   }
377   memset(&g, 0, sizeof(g));
378 
379   Tcl_LinkVar(interp, "disable_mutex_init",
380               (char*)&g.disableInit, TCL_LINK_INT);
381   Tcl_LinkVar(interp, "disable_mutex_try",
382               (char*)&g.disableTry, TCL_LINK_INT);
383   return SQLITE_OK;
384 }
385