- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / sqlite / src / src / test_mutex.c
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 ** This file contains test logic for the sqlite3_mutex interfaces.
13 */
14
15 #include "tcl.h"
16 #include "sqlite3.h"
17 #include "sqliteInt.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 disableTry;               /* True to force sqlite3_mutex_try() 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 = {0};
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   if( g.disableTry ) return SQLITE_BUSY;
124   return g.m.xMutexTry(p->pReal);
125 }
126
127 /* Leave a mutex
128 */
129 static void counterMutexLeave(sqlite3_mutex *p){
130   assert( g.isInit );
131   g.m.xMutexLeave(p->pReal);
132 }
133
134 /*
135 ** sqlite3_shutdown
136 */
137 static int test_shutdown(
138   void * clientData,
139   Tcl_Interp *interp,
140   int objc,
141   Tcl_Obj *CONST objv[]
142 ){
143   int rc;
144
145   if( objc!=1 ){
146     Tcl_WrongNumArgs(interp, 1, objv, "");
147     return TCL_ERROR;
148   }
149
150   rc = sqlite3_shutdown();
151   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
152   return TCL_OK;
153 }
154
155 /*
156 ** sqlite3_initialize
157 */
158 static int test_initialize(
159   void * clientData,
160   Tcl_Interp *interp,
161   int objc,
162   Tcl_Obj *CONST objv[]
163 ){
164   int rc;
165
166   if( objc!=1 ){
167     Tcl_WrongNumArgs(interp, 1, objv, "");
168     return TCL_ERROR;
169   }
170
171   rc = sqlite3_initialize();
172   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
173   return TCL_OK;
174 }
175
176 /*
177 ** install_mutex_counters BOOLEAN
178 */
179 static int test_install_mutex_counters(
180   void * clientData,
181   Tcl_Interp *interp,
182   int objc,
183   Tcl_Obj *CONST objv[]
184 ){
185   int rc = SQLITE_OK;
186   int isInstall;
187
188   sqlite3_mutex_methods counter_methods = {
189     counterMutexInit,
190     counterMutexEnd,
191     counterMutexAlloc,
192     counterMutexFree,
193     counterMutexEnter,
194     counterMutexTry,
195     counterMutexLeave,
196     counterMutexHeld,
197     counterMutexNotheld
198   };
199
200   if( objc!=2 ){
201     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
202     return TCL_ERROR;
203   }
204   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
205     return TCL_ERROR;
206   }
207
208   assert(isInstall==0 || isInstall==1);
209   assert(g.isInstalled==0 || g.isInstalled==1);
210   if( isInstall==g.isInstalled ){
211     Tcl_AppendResult(interp, "mutex counters are ", 0);
212     Tcl_AppendResult(interp, isInstall?"already installed":"not installed", 0);
213     return TCL_ERROR;
214   }
215
216   if( isInstall ){
217     assert( g.m.xMutexAlloc==0 );
218     rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m);
219     if( rc==SQLITE_OK ){
220       sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods);
221     }
222     g.disableTry = 0;
223   }else{
224     assert( g.m.xMutexAlloc );
225     rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m);
226     memset(&g.m, 0, sizeof(sqlite3_mutex_methods));
227   }
228
229   if( rc==SQLITE_OK ){
230     g.isInstalled = isInstall;
231   }
232
233   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
234   return TCL_OK;
235 }
236
237 /*
238 ** read_mutex_counters
239 */
240 static int test_read_mutex_counters(
241   void * clientData,
242   Tcl_Interp *interp,
243   int objc,
244   Tcl_Obj *CONST objv[]
245 ){
246   Tcl_Obj *pRet;
247   int ii;
248   char *aName[8] = {
249     "fast",        "recursive",   "static_master", "static_mem", 
250     "static_open", "static_prng", "static_lru",    "static_pmem"
251   };
252
253   if( objc!=1 ){
254     Tcl_WrongNumArgs(interp, 1, objv, "");
255     return TCL_ERROR;
256   }
257
258   pRet = Tcl_NewObj();
259   Tcl_IncrRefCount(pRet);
260   for(ii=0; ii<8; ii++){
261     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1));
262     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii]));
263   }
264   Tcl_SetObjResult(interp, pRet);
265   Tcl_DecrRefCount(pRet);
266
267   return TCL_OK;
268 }
269
270 /*
271 ** clear_mutex_counters
272 */
273 static int test_clear_mutex_counters(
274   void * clientData,
275   Tcl_Interp *interp,
276   int objc,
277   Tcl_Obj *CONST objv[]
278 ){
279   int ii;
280
281   if( objc!=1 ){
282     Tcl_WrongNumArgs(interp, 1, objv, "");
283     return TCL_ERROR;
284   }
285
286   for(ii=0; ii<8; ii++){
287     g.aCounter[ii] = 0;
288   }
289   return TCL_OK;
290 }
291
292 /*
293 ** Create and free a mutex.  Return the mutex pointer.  The pointer
294 ** will be invalid since the mutex has already been freed.  The
295 ** return pointer just checks to see if the mutex really was allocated.
296 */
297 static int test_alloc_mutex(
298   void * clientData,
299   Tcl_Interp *interp,
300   int objc,
301   Tcl_Obj *CONST objv[]
302 ){
303 #if SQLITE_THREADSAFE
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 #endif
310   return TCL_OK;
311 }
312
313 /*
314 ** sqlite3_config OPTION
315 **
316 ** OPTION can be either one of the keywords:
317 **
318 **            SQLITE_CONFIG_SINGLETHREAD
319 **            SQLITE_CONFIG_MULTITHREAD
320 **            SQLITE_CONFIG_SERIALIZED
321 **
322 ** Or OPTION can be an raw integer.
323 */
324 static int test_config(
325   void * clientData,
326   Tcl_Interp *interp,
327   int objc,
328   Tcl_Obj *CONST objv[]
329 ){
330   struct ConfigOption {
331     const char *zName;
332     int iValue;
333   } aOpt[] = {
334     {"singlethread", SQLITE_CONFIG_SINGLETHREAD},
335     {"multithread",  SQLITE_CONFIG_MULTITHREAD},
336     {"serialized",   SQLITE_CONFIG_SERIALIZED},
337     {0, 0}
338   };
339   int s = sizeof(struct ConfigOption);
340   int i;
341   int rc;
342
343   if( objc!=2 ){
344     Tcl_WrongNumArgs(interp, 1, objv, "");
345     return TCL_ERROR;
346   }
347
348   if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){
349     if( Tcl_GetIntFromObj(interp, objv[1], &i) ){
350       return TCL_ERROR;
351     }
352   }else{
353     i = aOpt[i].iValue;
354   }
355
356   rc = sqlite3_config(i);
357   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
358   return TCL_OK;
359 }
360
361 static sqlite3 *getDbPointer(Tcl_Interp *pInterp, Tcl_Obj *pObj){
362   sqlite3 *db;
363   Tcl_CmdInfo info;
364   char *zCmd = Tcl_GetString(pObj);
365   if( Tcl_GetCommandInfo(pInterp, zCmd, &info) ){
366     db = *((sqlite3 **)info.objClientData);
367   }else{
368     db = (sqlite3*)sqlite3TestTextToPtr(zCmd);
369   }
370   assert( db );
371   return db;
372 }
373
374 static int test_enter_db_mutex(
375   void * clientData,
376   Tcl_Interp *interp,
377   int objc,
378   Tcl_Obj *CONST objv[]
379 ){
380   sqlite3 *db;
381   if( objc!=2 ){
382     Tcl_WrongNumArgs(interp, 1, objv, "DB");
383     return TCL_ERROR;
384   }
385   db = getDbPointer(interp, objv[1]);
386   if( !db ){
387     return TCL_ERROR;
388   }
389   sqlite3_mutex_enter(sqlite3_db_mutex(db));
390   return TCL_OK;
391 }
392
393 static int test_leave_db_mutex(
394   void * clientData,
395   Tcl_Interp *interp,
396   int objc,
397   Tcl_Obj *CONST objv[]
398 ){
399   sqlite3 *db;
400   if( objc!=2 ){
401     Tcl_WrongNumArgs(interp, 1, objv, "DB");
402     return TCL_ERROR;
403   }
404   db = getDbPointer(interp, objv[1]);
405   if( !db ){
406     return TCL_ERROR;
407   }
408   sqlite3_mutex_leave(sqlite3_db_mutex(db));
409   return TCL_OK;
410 }
411
412 int Sqlitetest_mutex_Init(Tcl_Interp *interp){
413   static struct {
414     char *zName;
415     Tcl_ObjCmdProc *xProc;
416   } aCmd[] = {
417     { "sqlite3_shutdown",        (Tcl_ObjCmdProc*)test_shutdown },
418     { "sqlite3_initialize",      (Tcl_ObjCmdProc*)test_initialize },
419     { "sqlite3_config",          (Tcl_ObjCmdProc*)test_config },
420
421     { "enter_db_mutex",          (Tcl_ObjCmdProc*)test_enter_db_mutex },
422     { "leave_db_mutex",          (Tcl_ObjCmdProc*)test_leave_db_mutex },
423
424     { "alloc_dealloc_mutex",     (Tcl_ObjCmdProc*)test_alloc_mutex },
425     { "install_mutex_counters",  (Tcl_ObjCmdProc*)test_install_mutex_counters },
426     { "read_mutex_counters",     (Tcl_ObjCmdProc*)test_read_mutex_counters },
427     { "clear_mutex_counters",    (Tcl_ObjCmdProc*)test_clear_mutex_counters },
428   };
429   int i;
430   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
431     Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
432   }
433
434   Tcl_LinkVar(interp, "disable_mutex_init", 
435               (char*)&g.disableInit, TCL_LINK_INT);
436   Tcl_LinkVar(interp, "disable_mutex_try", 
437               (char*)&g.disableTry, TCL_LINK_INT);
438   return SQLITE_OK;
439 }