xref: /sqlite-3.40.0/src/test_mutex.c (revision 9a6284c1)
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.7 2008/07/10 17:52:49 danielk1977 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 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   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 ** Create and free a mutex.  Return the mutex pointer.  The pointer
292 ** will be invalid since the mutex has already been freed.  The
293 ** return pointer just checks to see if the mutex really was allocated.
294 */
295 static int test_alloc_mutex(
296   void * clientData,
297   Tcl_Interp *interp,
298   int objc,
299   Tcl_Obj *CONST objv[]
300 ){
301   sqlite3_mutex *p = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
302   char zBuf[100];
303   sqlite3_mutex_free(p);
304   sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p);
305   Tcl_AppendResult(interp, zBuf, (char*)0);
306   return TCL_OK;
307 }
308 
309 /*
310 ** sqlite3_config OPTION
311 */
312 static int test_config(
313   void * clientData,
314   Tcl_Interp *interp,
315   int objc,
316   Tcl_Obj *CONST objv[]
317 ){
318   struct ConfigOption {
319     const char *zName;
320     int iValue;
321   } aOpt[] = {
322     {"singlethread", SQLITE_CONFIG_SINGLETHREAD},
323     {"multithread",  SQLITE_CONFIG_MULTITHREAD},
324     {"serialized",   SQLITE_CONFIG_SERIALIZED},
325     {0, 0}
326   };
327   int s = sizeof(struct ConfigOption);
328   int i;
329   int rc;
330 
331   if( objc!=2 ){
332     Tcl_WrongNumArgs(interp, 1, objv, "");
333     return TCL_ERROR;
334   }
335 
336   if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){
337     return TCL_ERROR;
338   }
339 
340   rc = sqlite3_config(aOpt[i].iValue);
341   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
342   return TCL_OK;
343 }
344 
345 int Sqlitetest_mutex_Init(Tcl_Interp *interp){
346   static struct {
347     char *zName;
348     Tcl_ObjCmdProc *xProc;
349   } aCmd[] = {
350     { "sqlite3_shutdown",        (Tcl_ObjCmdProc*)test_shutdown },
351     { "sqlite3_initialize",      (Tcl_ObjCmdProc*)test_initialize },
352     { "sqlite3_config",          (Tcl_ObjCmdProc*)test_config },
353 
354     { "alloc_dealloc_mutex",     (Tcl_ObjCmdProc*)test_alloc_mutex },
355     { "install_mutex_counters",  (Tcl_ObjCmdProc*)test_install_mutex_counters },
356     { "read_mutex_counters",     (Tcl_ObjCmdProc*)test_read_mutex_counters },
357     { "clear_mutex_counters",    (Tcl_ObjCmdProc*)test_clear_mutex_counters },
358   };
359   int i;
360   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
361     Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
362   }
363   memset(&g, 0, sizeof(g));
364 
365   Tcl_LinkVar(interp, "disable_mutex_init",
366               (char*)&g.disableInit, TCL_LINK_INT);
367   return SQLITE_OK;
368 }
369