xref: /sqlite-3.40.0/src/test_mutex.c (revision fb45d8c5)
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.5 2008/07/08 00:06: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 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   assert( g.isInit );
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==0 || eType==1 ){
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==0 || p->eType==1 ){
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   return g.m.xMutexTry(p->pReal);
124 }
125 
126 /* Leave a mutex
127 */
128 static void counterMutexLeave(sqlite3_mutex *p){
129   assert( g.isInit );
130   g.m.xMutexLeave(p->pReal);
131 }
132 
133 /*
134 ** sqlite3_shutdown
135 */
136 static int test_shutdown(
137   void * clientData,
138   Tcl_Interp *interp,
139   int objc,
140   Tcl_Obj *CONST objv[]
141 ){
142   int rc;
143 
144   if( objc!=1 ){
145     Tcl_WrongNumArgs(interp, 1, objv, "");
146     return TCL_ERROR;
147   }
148 
149   rc = sqlite3_shutdown();
150   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
151   return TCL_OK;
152 }
153 
154 /*
155 ** sqlite3_initialize
156 */
157 static int test_initialize(
158   void * clientData,
159   Tcl_Interp *interp,
160   int objc,
161   Tcl_Obj *CONST objv[]
162 ){
163   int rc;
164 
165   if( objc!=1 ){
166     Tcl_WrongNumArgs(interp, 1, objv, "");
167     return TCL_ERROR;
168   }
169 
170   rc = sqlite3_initialize();
171   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
172   return TCL_OK;
173 }
174 
175 /*
176 ** install_mutex_counters BOOLEAN
177 */
178 static int test_install_mutex_counters(
179   void * clientData,
180   Tcl_Interp *interp,
181   int objc,
182   Tcl_Obj *CONST objv[]
183 ){
184   int rc = SQLITE_OK;
185   int isInstall;
186 
187   sqlite3_mutex_methods counter_methods = {
188     counterMutexInit,
189     counterMutexEnd,
190     counterMutexAlloc,
191     counterMutexFree,
192     counterMutexEnter,
193     counterMutexTry,
194     counterMutexLeave,
195     counterMutexHeld,
196     counterMutexNotheld
197   };
198 
199   if( objc!=2 ){
200     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
201     return TCL_ERROR;
202   }
203   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
204     return TCL_ERROR;
205   }
206 
207   assert(isInstall==0 || isInstall==1);
208   assert(g.isInstalled==0 || g.isInstalled==1);
209   if( isInstall==g.isInstalled ){
210     Tcl_AppendResult(interp, "mutex counters are ", 0);
211     Tcl_AppendResult(interp, isInstall?"already installed":"not installed", 0);
212     return TCL_ERROR;
213   }
214 
215   if( isInstall ){
216     assert( g.m.xMutexAlloc==0 );
217     rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m);
218     if( rc==SQLITE_OK ){
219       sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods);
220     }
221   }else{
222     assert( g.m.xMutexAlloc );
223     rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m);
224     memset(&g.m, 0, sizeof(sqlite3_mutex_methods));
225   }
226 
227   if( rc==SQLITE_OK ){
228     g.isInstalled = isInstall;
229   }
230 
231   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
232   return TCL_OK;
233 }
234 
235 /*
236 ** read_mutex_counters
237 */
238 static int test_read_mutex_counters(
239   void * clientData,
240   Tcl_Interp *interp,
241   int objc,
242   Tcl_Obj *CONST objv[]
243 ){
244   Tcl_Obj *pRet;
245   int ii;
246   char *aName[8] = {
247     "fast",        "recursive",   "static_master", "static_mem",
248     "static_mem2", "static_prng", "static_lru",    "static_lru2"
249   };
250 
251   if( objc!=1 ){
252     Tcl_WrongNumArgs(interp, 1, objv, "");
253     return TCL_ERROR;
254   }
255 
256   pRet = Tcl_NewObj();
257   Tcl_IncrRefCount(pRet);
258   for(ii=0; ii<8; ii++){
259     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1));
260     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii]));
261   }
262   Tcl_SetObjResult(interp, pRet);
263   Tcl_DecrRefCount(pRet);
264 
265   return TCL_OK;
266 }
267 
268 /*
269 ** clear_mutex_counters
270 */
271 static int test_clear_mutex_counters(
272   void * clientData,
273   Tcl_Interp *interp,
274   int objc,
275   Tcl_Obj *CONST objv[]
276 ){
277   int ii;
278 
279   if( objc!=1 ){
280     Tcl_WrongNumArgs(interp, 1, objv, "");
281     return TCL_ERROR;
282   }
283 
284   for(ii=0; ii<8; ii++){
285     g.aCounter[ii] = 0;
286   }
287   return TCL_OK;
288 }
289 
290 /*
291 ** sqlite3_config OPTION
292 */
293 static int test_config(
294   void * clientData,
295   Tcl_Interp *interp,
296   int objc,
297   Tcl_Obj *CONST objv[]
298 ){
299   struct ConfigOption {
300     const char *zName;
301     int iValue;
302   } aOpt[] = {
303     {"singlethread", SQLITE_CONFIG_SINGLETHREAD},
304     {"multithread",  SQLITE_CONFIG_MULTITHREAD},
305     {"serialized",   SQLITE_CONFIG_SERIALIZED},
306     {0, 0}
307   };
308   int s = sizeof(struct ConfigOption);
309   int i;
310   int rc;
311 
312   if( objc!=2 ){
313     Tcl_WrongNumArgs(interp, 1, objv, "");
314     return TCL_ERROR;
315   }
316 
317   if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){
318     return TCL_ERROR;
319   }
320 
321   rc = sqlite3_config(aOpt[i].iValue);
322   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
323   return TCL_OK;
324 }
325 
326 int Sqlitetest_mutex_Init(Tcl_Interp *interp){
327   static struct {
328     char *zName;
329     Tcl_ObjCmdProc *xProc;
330   } aCmd[] = {
331     { "sqlite3_shutdown",        (Tcl_ObjCmdProc*)test_shutdown },
332     { "sqlite3_initialize",      (Tcl_ObjCmdProc*)test_initialize },
333     { "sqlite3_config",          (Tcl_ObjCmdProc*)test_config },
334 
335     { "install_mutex_counters",  (Tcl_ObjCmdProc*)test_install_mutex_counters },
336     { "read_mutex_counters",     (Tcl_ObjCmdProc*)test_read_mutex_counters },
337     { "clear_mutex_counters",    (Tcl_ObjCmdProc*)test_clear_mutex_counters },
338   };
339   int i;
340   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
341     Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
342   }
343   memset(&g, 0, sizeof(g));
344 
345   Tcl_LinkVar(interp, "disable_mutex_init",
346               (char*)&g.disableInit, TCL_LINK_INT);
347   return SQLITE_OK;
348 }
349