xref: /sqlite-3.40.0/src/test_mutex.c (revision b21e7c70)
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.4 2008/06/22 12:37:58 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 const char *sqlite3TestErrorName(int);
23 
24 struct sqlite3_mutex {
25   sqlite3_mutex *pReal;
26   int eType;
27 };
28 
29 static struct test_mutex_globals {
30   int isInstalled;
31   sqlite3_mutex_methods m;          /* Interface to "real" mutex system */
32   int aCounter[8];                  /* Number of grabs of each type of mutex */
33   sqlite3_mutex aStatic[6];         /* The six static mutexes */
34 } g;
35 
36 static int counterMutexHeld(sqlite3_mutex *p){
37   return g.m.xMutexHeld(p->pReal);
38 }
39 
40 static int counterMutexNotheld(sqlite3_mutex *p){
41   return g.m.xMutexNotheld(p->pReal);
42 }
43 
44 static int counterMutexInit(void){
45   return g.m.xMutexInit();
46 }
47 
48 static int counterMutexEnd(void){
49   return g.m.xMutexEnd();
50 }
51 
52 static sqlite3_mutex *counterMutexAlloc(int eType){
53   sqlite3_mutex *pReal;
54   sqlite3_mutex *pRet = 0;
55 
56   assert(eType<8 && eType>=0);
57 
58   pReal = g.m.xMutexAlloc(eType);
59   if( !pReal ) return 0;
60 
61   if( eType==0 || eType==1 ){
62     pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex));
63   }else{
64     pRet = &g.aStatic[eType-2];
65   }
66 
67   pRet->eType = eType;
68   pRet->pReal = pReal;
69   return pRet;
70 }
71 
72 static void counterMutexFree(sqlite3_mutex *p){
73   g.m.xMutexFree(p->pReal);
74   if( p->eType==0 || p->eType==1 ){
75     free(p);
76   }
77 }
78 
79 static void counterMutexEnter(sqlite3_mutex *p){
80   g.aCounter[p->eType]++;
81   g.m.xMutexEnter(p->pReal);
82 }
83 
84 static int counterMutexTry(sqlite3_mutex *p){
85   g.aCounter[p->eType]++;
86   return g.m.xMutexTry(p->pReal);
87 }
88 
89 static void counterMutexLeave(sqlite3_mutex *p){
90   g.m.xMutexLeave(p->pReal);
91 }
92 
93 /*
94 ** sqlite3_shutdown
95 */
96 static int test_shutdown(
97   void * clientData,
98   Tcl_Interp *interp,
99   int objc,
100   Tcl_Obj *CONST objv[]
101 ){
102   int rc;
103 
104   if( objc!=1 ){
105     Tcl_WrongNumArgs(interp, 1, objv, "");
106     return TCL_ERROR;
107   }
108 
109   rc = sqlite3_shutdown();
110   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
111   return TCL_OK;
112 }
113 
114 /*
115 ** sqlite3_initialize
116 */
117 static int test_initialize(
118   void * clientData,
119   Tcl_Interp *interp,
120   int objc,
121   Tcl_Obj *CONST objv[]
122 ){
123   int rc;
124 
125   if( objc!=1 ){
126     Tcl_WrongNumArgs(interp, 1, objv, "");
127     return TCL_ERROR;
128   }
129 
130   rc = sqlite3_initialize();
131   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
132   return TCL_OK;
133 }
134 
135 /*
136 ** install_mutex_counters BOOLEAN
137 */
138 static int test_install_mutex_counters(
139   void * clientData,
140   Tcl_Interp *interp,
141   int objc,
142   Tcl_Obj *CONST objv[]
143 ){
144   int rc = SQLITE_OK;
145   int isInstall;
146 
147   sqlite3_mutex_methods counter_methods = {
148     counterMutexInit,
149     counterMutexEnd,
150     counterMutexAlloc,
151     counterMutexFree,
152     counterMutexEnter,
153     counterMutexTry,
154     counterMutexLeave,
155     counterMutexHeld,
156     counterMutexNotheld
157   };
158 
159   if( objc!=2 ){
160     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
161     return TCL_ERROR;
162   }
163   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
164     return TCL_ERROR;
165   }
166 
167   assert(isInstall==0 || isInstall==1);
168   assert(g.isInstalled==0 || g.isInstalled==1);
169   if( isInstall==g.isInstalled ){
170     Tcl_AppendResult(interp, "mutex counters are ", 0);
171     Tcl_AppendResult(interp, isInstall?"already installed":"not installed", 0);
172     return TCL_ERROR;
173   }
174 
175   if( isInstall ){
176     assert( g.m.xMutexAlloc==0 );
177     rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m);
178     if( rc==SQLITE_OK ){
179       sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods);
180     }
181   }else{
182     assert( g.m.xMutexAlloc );
183     rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m);
184     memset(&g.m, 0, sizeof(sqlite3_mutex_methods));
185   }
186 
187   if( rc==SQLITE_OK ){
188     g.isInstalled = isInstall;
189   }
190 
191   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
192   return TCL_OK;
193 }
194 
195 /*
196 ** read_mutex_counters
197 */
198 static int test_read_mutex_counters(
199   void * clientData,
200   Tcl_Interp *interp,
201   int objc,
202   Tcl_Obj *CONST objv[]
203 ){
204   Tcl_Obj *pRet;
205   int ii;
206   char *aName[8] = {
207     "fast",        "recursive",   "static_master", "static_mem",
208     "static_mem2", "static_prng", "static_lru",    "static_lru2"
209   };
210 
211   if( objc!=1 ){
212     Tcl_WrongNumArgs(interp, 1, objv, "");
213     return TCL_ERROR;
214   }
215 
216   pRet = Tcl_NewObj();
217   Tcl_IncrRefCount(pRet);
218   for(ii=0; ii<8; ii++){
219     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1));
220     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii]));
221   }
222   Tcl_SetObjResult(interp, pRet);
223   Tcl_DecrRefCount(pRet);
224 
225   return TCL_OK;
226 }
227 
228 /*
229 ** clear_mutex_counters
230 */
231 static int test_clear_mutex_counters(
232   void * clientData,
233   Tcl_Interp *interp,
234   int objc,
235   Tcl_Obj *CONST objv[]
236 ){
237   int ii;
238 
239   if( objc!=1 ){
240     Tcl_WrongNumArgs(interp, 1, objv, "");
241     return TCL_ERROR;
242   }
243 
244   for(ii=0; ii<8; ii++){
245     g.aCounter[ii] = 0;
246   }
247   return TCL_OK;
248 }
249 
250 /*
251 ** sqlite3_config OPTION
252 */
253 static int test_config(
254   void * clientData,
255   Tcl_Interp *interp,
256   int objc,
257   Tcl_Obj *CONST objv[]
258 ){
259   struct ConfigOption {
260     const char *zName;
261     int iValue;
262   } aOpt[] = {
263     {"singlethread", SQLITE_CONFIG_SINGLETHREAD},
264     {"multithread",  SQLITE_CONFIG_MULTITHREAD},
265     {"serialized",   SQLITE_CONFIG_SERIALIZED},
266     {0, 0}
267   };
268   int s = sizeof(struct ConfigOption);
269   int i;
270   int rc;
271 
272   if( objc!=2 ){
273     Tcl_WrongNumArgs(interp, 1, objv, "");
274     return TCL_ERROR;
275   }
276 
277   if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){
278     return TCL_ERROR;
279   }
280 
281   rc = sqlite3_config(aOpt[i].iValue);
282   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
283   return TCL_OK;
284 }
285 
286 int Sqlitetest_mutex_Init(Tcl_Interp *interp){
287   static struct {
288     char *zName;
289     Tcl_ObjCmdProc *xProc;
290   } aCmd[] = {
291     { "sqlite3_shutdown",        (Tcl_ObjCmdProc*)test_shutdown },
292     { "sqlite3_initialize",      (Tcl_ObjCmdProc*)test_initialize },
293     { "sqlite3_config",          (Tcl_ObjCmdProc*)test_config },
294 
295     { "install_mutex_counters",  (Tcl_ObjCmdProc*)test_install_mutex_counters },
296     { "read_mutex_counters",     (Tcl_ObjCmdProc*)test_read_mutex_counters },
297     { "clear_mutex_counters",    (Tcl_ObjCmdProc*)test_clear_mutex_counters },
298   };
299   int i;
300   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
301     Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
302   }
303   memset(&g, 0, sizeof(g));
304   return SQLITE_OK;
305 }
306