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