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