4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
11 *************************************************************************
12 ** This file contains test logic for the sqlite3_mutex interfaces.
17 #include "sqliteInt.h"
22 /* defined in test1.c */
23 const char *sqlite3TestErrorName(int);
25 /* A countable mutex */
26 struct sqlite3_mutex {
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 */
42 /* Return true if the countable mutex is currently held */
43 static int counterMutexHeld(sqlite3_mutex *p){
44 return g.m.xMutexHeld(p->pReal);
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);
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.
57 static int counterMutexInit(void){
59 if( g.disableInit ) return g.disableInit;
60 rc = g.m.xMutexInit();
66 ** Uninitialize the mutex subsystem
68 static int counterMutexEnd(void){
70 return g.m.xMutexEnd();
74 ** Allocate a countable mutex
76 static sqlite3_mutex *counterMutexAlloc(int eType){
78 sqlite3_mutex *pRet = 0;
81 assert(eType<8 && eType>=0);
83 pReal = g.m.xMutexAlloc(eType);
84 if( !pReal ) return 0;
86 if( eType==SQLITE_MUTEX_FAST || eType==SQLITE_MUTEX_RECURSIVE ){
87 pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex));
89 pRet = &g.aStatic[eType-2];
98 ** Free a countable mutex
100 static void counterMutexFree(sqlite3_mutex *p){
102 g.m.xMutexFree(p->pReal);
103 if( p->eType==SQLITE_MUTEX_FAST || p->eType==SQLITE_MUTEX_RECURSIVE ){
109 ** Enter a countable mutex. Block until entry is safe.
111 static void counterMutexEnter(sqlite3_mutex *p){
113 g.aCounter[p->eType]++;
114 g.m.xMutexEnter(p->pReal);
118 ** Try to enter a mutex. Return true on success.
120 static int counterMutexTry(sqlite3_mutex *p){
122 g.aCounter[p->eType]++;
123 if( g.disableTry ) return SQLITE_BUSY;
124 return g.m.xMutexTry(p->pReal);
129 static void counterMutexLeave(sqlite3_mutex *p){
131 g.m.xMutexLeave(p->pReal);
137 static int test_shutdown(
141 Tcl_Obj *CONST objv[]
146 Tcl_WrongNumArgs(interp, 1, objv, "");
150 rc = sqlite3_shutdown();
151 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
156 ** sqlite3_initialize
158 static int test_initialize(
162 Tcl_Obj *CONST objv[]
167 Tcl_WrongNumArgs(interp, 1, objv, "");
171 rc = sqlite3_initialize();
172 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
177 ** install_mutex_counters BOOLEAN
179 static int test_install_mutex_counters(
183 Tcl_Obj *CONST objv[]
188 sqlite3_mutex_methods counter_methods = {
201 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
204 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
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);
217 assert( g.m.xMutexAlloc==0 );
218 rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m);
220 sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods);
224 assert( g.m.xMutexAlloc );
225 rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m);
226 memset(&g.m, 0, sizeof(sqlite3_mutex_methods));
230 g.isInstalled = isInstall;
233 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
238 ** read_mutex_counters
240 static int test_read_mutex_counters(
244 Tcl_Obj *CONST objv[]
249 "fast", "recursive", "static_master", "static_mem",
250 "static_open", "static_prng", "static_lru", "static_pmem"
254 Tcl_WrongNumArgs(interp, 1, objv, "");
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]));
264 Tcl_SetObjResult(interp, pRet);
265 Tcl_DecrRefCount(pRet);
271 ** clear_mutex_counters
273 static int test_clear_mutex_counters(
277 Tcl_Obj *CONST objv[]
282 Tcl_WrongNumArgs(interp, 1, objv, "");
286 for(ii=0; ii<8; ii++){
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.
297 static int test_alloc_mutex(
301 Tcl_Obj *CONST objv[]
303 #if SQLITE_THREADSAFE
304 sqlite3_mutex *p = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
306 sqlite3_mutex_free(p);
307 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p);
308 Tcl_AppendResult(interp, zBuf, (char*)0);
314 ** sqlite3_config OPTION
316 ** OPTION can be either one of the keywords:
318 ** SQLITE_CONFIG_SINGLETHREAD
319 ** SQLITE_CONFIG_MULTITHREAD
320 ** SQLITE_CONFIG_SERIALIZED
322 ** Or OPTION can be an raw integer.
324 static int test_config(
328 Tcl_Obj *CONST objv[]
330 struct ConfigOption {
334 {"singlethread", SQLITE_CONFIG_SINGLETHREAD},
335 {"multithread", SQLITE_CONFIG_MULTITHREAD},
336 {"serialized", SQLITE_CONFIG_SERIALIZED},
339 int s = sizeof(struct ConfigOption);
344 Tcl_WrongNumArgs(interp, 1, objv, "");
348 if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){
349 if( Tcl_GetIntFromObj(interp, objv[1], &i) ){
356 rc = sqlite3_config(i);
357 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
361 static sqlite3 *getDbPointer(Tcl_Interp *pInterp, Tcl_Obj *pObj){
364 char *zCmd = Tcl_GetString(pObj);
365 if( Tcl_GetCommandInfo(pInterp, zCmd, &info) ){
366 db = *((sqlite3 **)info.objClientData);
368 db = (sqlite3*)sqlite3TestTextToPtr(zCmd);
374 static int test_enter_db_mutex(
378 Tcl_Obj *CONST objv[]
382 Tcl_WrongNumArgs(interp, 1, objv, "DB");
385 db = getDbPointer(interp, objv[1]);
389 sqlite3_mutex_enter(sqlite3_db_mutex(db));
393 static int test_leave_db_mutex(
397 Tcl_Obj *CONST objv[]
401 Tcl_WrongNumArgs(interp, 1, objv, "DB");
404 db = getDbPointer(interp, objv[1]);
408 sqlite3_mutex_leave(sqlite3_db_mutex(db));
412 int Sqlitetest_mutex_Init(Tcl_Interp *interp){
415 Tcl_ObjCmdProc *xProc;
417 { "sqlite3_shutdown", (Tcl_ObjCmdProc*)test_shutdown },
418 { "sqlite3_initialize", (Tcl_ObjCmdProc*)test_initialize },
419 { "sqlite3_config", (Tcl_ObjCmdProc*)test_config },
421 { "enter_db_mutex", (Tcl_ObjCmdProc*)test_enter_db_mutex },
422 { "leave_db_mutex", (Tcl_ObjCmdProc*)test_leave_db_mutex },
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 },
430 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
431 Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
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);