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 main.c */
23 extern const char *sqlite3ErrName(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 *)sqlite3ErrName(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 *)sqlite3ErrName(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 *)sqlite3ErrName(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 *)sqlite3ErrName(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
);