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.
15 #if defined(INCLUDE_SQLITE_TCL_H)
16 # include "sqlite_tcl.h"
21 #include "sqliteInt.h"
26 #define MAX_MUTEXES (SQLITE_MUTEX_STATIC_VFS3+1)
27 #define STATIC_MUTEXES (MAX_MUTEXES-(SQLITE_MUTEX_RECURSIVE+1))
29 /* defined in main.c */
30 extern const char *sqlite3ErrName(int);
32 static const char *aName
[MAX_MUTEXES
+1] = {
33 "fast", "recursive", "static_master", "static_mem",
34 "static_open", "static_prng", "static_lru", "static_pmem",
35 "static_app1", "static_app2", "static_app3", "static_vfs1",
36 "static_vfs2", "static_vfs3", 0
39 /* A countable mutex */
40 struct sqlite3_mutex
{
46 static struct test_mutex_globals
{
47 int isInstalled
; /* True if installed */
48 int disableInit
; /* True to cause sqlite3_initalize() to fail */
49 int disableTry
; /* True to force sqlite3_mutex_try() to fail */
50 int isInit
; /* True if initialized */
51 sqlite3_mutex_methods m
; /* Interface to "real" mutex system */
52 int aCounter
[MAX_MUTEXES
]; /* Number of grabs of each type of mutex */
53 sqlite3_mutex aStatic
[STATIC_MUTEXES
]; /* The static mutexes */
56 /* Return true if the countable mutex is currently held */
57 static int counterMutexHeld(sqlite3_mutex
*p
){
58 return g
.m
.xMutexHeld(p
->pReal
);
61 /* Return true if the countable mutex is not currently held */
62 static int counterMutexNotheld(sqlite3_mutex
*p
){
63 return g
.m
.xMutexNotheld(p
->pReal
);
66 /* Initialize the countable mutex interface
67 ** Or, if g.disableInit is non-zero, then do not initialize but instead
68 ** return the value of g.disableInit as the result code. This can be used
69 ** to simulate an initialization failure.
71 static int counterMutexInit(void){
73 if( g
.disableInit
) return g
.disableInit
;
74 rc
= g
.m
.xMutexInit();
80 ** Uninitialize the mutex subsystem
82 static int counterMutexEnd(void){
84 return g
.m
.xMutexEnd();
88 ** Allocate a countable mutex
90 static sqlite3_mutex
*counterMutexAlloc(int eType
){
92 sqlite3_mutex
*pRet
= 0;
95 assert( eType
>=SQLITE_MUTEX_FAST
);
96 assert( eType
<=SQLITE_MUTEX_STATIC_VFS3
);
98 pReal
= g
.m
.xMutexAlloc(eType
);
99 if( !pReal
) return 0;
101 if( eType
==SQLITE_MUTEX_FAST
|| eType
==SQLITE_MUTEX_RECURSIVE
){
102 pRet
= (sqlite3_mutex
*)malloc(sizeof(sqlite3_mutex
));
104 int eStaticType
= eType
- (MAX_MUTEXES
- STATIC_MUTEXES
);
105 assert( eStaticType
>=0 );
106 assert( eStaticType
<STATIC_MUTEXES
);
107 pRet
= &g
.aStatic
[eStaticType
];
116 ** Free a countable mutex
118 static void counterMutexFree(sqlite3_mutex
*p
){
120 g
.m
.xMutexFree(p
->pReal
);
121 if( p
->eType
==SQLITE_MUTEX_FAST
|| p
->eType
==SQLITE_MUTEX_RECURSIVE
){
127 ** Enter a countable mutex. Block until entry is safe.
129 static void counterMutexEnter(sqlite3_mutex
*p
){
131 assert( p
->eType
>=0 );
132 assert( p
->eType
<MAX_MUTEXES
);
133 g
.aCounter
[p
->eType
]++;
134 g
.m
.xMutexEnter(p
->pReal
);
138 ** Try to enter a mutex. Return true on success.
140 static int counterMutexTry(sqlite3_mutex
*p
){
142 assert( p
->eType
>=0 );
143 assert( p
->eType
<MAX_MUTEXES
);
144 g
.aCounter
[p
->eType
]++;
145 if( g
.disableTry
) return SQLITE_BUSY
;
146 return g
.m
.xMutexTry(p
->pReal
);
151 static void counterMutexLeave(sqlite3_mutex
*p
){
153 g
.m
.xMutexLeave(p
->pReal
);
159 static int SQLITE_TCLAPI
test_shutdown(
163 Tcl_Obj
*CONST objv
[]
168 Tcl_WrongNumArgs(interp
, 1, objv
, "");
172 rc
= sqlite3_shutdown();
173 Tcl_SetResult(interp
, (char *)sqlite3ErrName(rc
), TCL_VOLATILE
);
178 ** sqlite3_initialize
180 static int SQLITE_TCLAPI
test_initialize(
184 Tcl_Obj
*CONST objv
[]
189 Tcl_WrongNumArgs(interp
, 1, objv
, "");
193 rc
= sqlite3_initialize();
194 Tcl_SetResult(interp
, (char *)sqlite3ErrName(rc
), TCL_VOLATILE
);
199 ** install_mutex_counters BOOLEAN
201 static int SQLITE_TCLAPI
test_install_mutex_counters(
205 Tcl_Obj
*CONST objv
[]
210 sqlite3_mutex_methods counter_methods
= {
223 Tcl_WrongNumArgs(interp
, 1, objv
, "BOOLEAN");
226 if( TCL_OK
!=Tcl_GetBooleanFromObj(interp
, objv
[1], &isInstall
) ){
230 assert(isInstall
==0 || isInstall
==1);
231 assert(g
.isInstalled
==0 || g
.isInstalled
==1);
232 if( isInstall
==g
.isInstalled
){
233 Tcl_AppendResult(interp
, "mutex counters are ", 0);
234 Tcl_AppendResult(interp
, isInstall
?"already installed":"not installed", 0);
239 assert( g
.m
.xMutexAlloc
==0 );
240 rc
= sqlite3_config(SQLITE_CONFIG_GETMUTEX
, &g
.m
);
242 sqlite3_config(SQLITE_CONFIG_MUTEX
, &counter_methods
);
246 assert( g
.m
.xMutexAlloc
);
247 rc
= sqlite3_config(SQLITE_CONFIG_MUTEX
, &g
.m
);
248 memset(&g
.m
, 0, sizeof(sqlite3_mutex_methods
));
252 g
.isInstalled
= isInstall
;
255 Tcl_SetResult(interp
, (char *)sqlite3ErrName(rc
), TCL_VOLATILE
);
260 ** read_mutex_counters
262 static int SQLITE_TCLAPI
test_read_mutex_counters(
266 Tcl_Obj
*CONST objv
[]
272 Tcl_WrongNumArgs(interp
, 1, objv
, "");
277 Tcl_IncrRefCount(pRet
);
278 for(ii
=0; ii
<MAX_MUTEXES
; ii
++){
279 Tcl_ListObjAppendElement(interp
, pRet
, Tcl_NewStringObj(aName
[ii
], -1));
280 Tcl_ListObjAppendElement(interp
, pRet
, Tcl_NewIntObj(g
.aCounter
[ii
]));
282 Tcl_SetObjResult(interp
, pRet
);
283 Tcl_DecrRefCount(pRet
);
289 ** clear_mutex_counters
291 static int SQLITE_TCLAPI
test_clear_mutex_counters(
295 Tcl_Obj
*CONST objv
[]
300 Tcl_WrongNumArgs(interp
, 1, objv
, "");
304 for(ii
=0; ii
<MAX_MUTEXES
; ii
++){
311 ** Create and free a mutex. Return the mutex pointer. The pointer
312 ** will be invalid since the mutex has already been freed. The
313 ** return pointer just checks to see if the mutex really was allocated.
315 static int SQLITE_TCLAPI
test_alloc_mutex(
319 Tcl_Obj
*CONST objv
[]
321 #if SQLITE_THREADSAFE
322 sqlite3_mutex
*p
= sqlite3_mutex_alloc(SQLITE_MUTEX_FAST
);
324 sqlite3_mutex_free(p
);
325 sqlite3_snprintf(sizeof(zBuf
), zBuf
, "%p", p
);
326 Tcl_AppendResult(interp
, zBuf
, (char*)0);
332 ** sqlite3_config OPTION
334 ** OPTION can be either one of the keywords:
336 ** SQLITE_CONFIG_SINGLETHREAD
337 ** SQLITE_CONFIG_MULTITHREAD
338 ** SQLITE_CONFIG_SERIALIZED
340 ** Or OPTION can be an raw integer.
342 static int SQLITE_TCLAPI
test_config(
346 Tcl_Obj
*CONST objv
[]
348 struct ConfigOption
{
352 {"singlethread", SQLITE_CONFIG_SINGLETHREAD
},
353 {"multithread", SQLITE_CONFIG_MULTITHREAD
},
354 {"serialized", SQLITE_CONFIG_SERIALIZED
},
357 int s
= sizeof(struct ConfigOption
);
362 Tcl_WrongNumArgs(interp
, 1, objv
, "");
366 if( Tcl_GetIndexFromObjStruct(interp
, objv
[1], aOpt
, s
, "flag", 0, &i
) ){
367 if( Tcl_GetIntFromObj(interp
, objv
[1], &i
) ){
374 rc
= sqlite3_config(i
);
375 Tcl_SetResult(interp
, (char *)sqlite3ErrName(rc
), TCL_VOLATILE
);
379 static sqlite3
*getDbPointer(Tcl_Interp
*pInterp
, Tcl_Obj
*pObj
){
382 char *zCmd
= Tcl_GetString(pObj
);
383 if( Tcl_GetCommandInfo(pInterp
, zCmd
, &info
) ){
384 db
= *((sqlite3
**)info
.objClientData
);
386 db
= (sqlite3
*)sqlite3TestTextToPtr(zCmd
);
392 static sqlite3_mutex
*getStaticMutexPointer(
397 if( Tcl_GetIndexFromObj(pInterp
, pObj
, aName
, "mutex name", 0, &iMutex
) ){
400 assert( iMutex
!=SQLITE_MUTEX_FAST
&& iMutex
!=SQLITE_MUTEX_RECURSIVE
);
401 return counterMutexAlloc(iMutex
);
404 static int SQLITE_TCLAPI
test_enter_static_mutex(
408 Tcl_Obj
*CONST objv
[]
410 sqlite3_mutex
*pMutex
;
412 Tcl_WrongNumArgs(interp
, 1, objv
, "NAME");
415 pMutex
= getStaticMutexPointer(interp
, objv
[1]);
419 sqlite3_mutex_enter(pMutex
);
423 static int SQLITE_TCLAPI
test_leave_static_mutex(
427 Tcl_Obj
*CONST objv
[]
429 sqlite3_mutex
*pMutex
;
431 Tcl_WrongNumArgs(interp
, 1, objv
, "NAME");
434 pMutex
= getStaticMutexPointer(interp
, objv
[1]);
438 sqlite3_mutex_leave(pMutex
);
442 static int SQLITE_TCLAPI
test_enter_db_mutex(
446 Tcl_Obj
*CONST objv
[]
450 Tcl_WrongNumArgs(interp
, 1, objv
, "DB");
453 db
= getDbPointer(interp
, objv
[1]);
457 sqlite3_mutex_enter(sqlite3_db_mutex(db
));
461 static int SQLITE_TCLAPI
test_leave_db_mutex(
465 Tcl_Obj
*CONST objv
[]
469 Tcl_WrongNumArgs(interp
, 1, objv
, "DB");
472 db
= getDbPointer(interp
, objv
[1]);
476 sqlite3_mutex_leave(sqlite3_db_mutex(db
));
480 int Sqlitetest_mutex_Init(Tcl_Interp
*interp
){
483 Tcl_ObjCmdProc
*xProc
;
485 { "sqlite3_shutdown", (Tcl_ObjCmdProc
*)test_shutdown
},
486 { "sqlite3_initialize", (Tcl_ObjCmdProc
*)test_initialize
},
487 { "sqlite3_config", (Tcl_ObjCmdProc
*)test_config
},
489 { "enter_static_mutex", (Tcl_ObjCmdProc
*)test_enter_static_mutex
},
490 { "leave_static_mutex", (Tcl_ObjCmdProc
*)test_leave_static_mutex
},
492 { "enter_db_mutex", (Tcl_ObjCmdProc
*)test_enter_db_mutex
},
493 { "leave_db_mutex", (Tcl_ObjCmdProc
*)test_leave_db_mutex
},
495 { "alloc_dealloc_mutex", (Tcl_ObjCmdProc
*)test_alloc_mutex
},
496 { "install_mutex_counters", (Tcl_ObjCmdProc
*)test_install_mutex_counters
},
497 { "read_mutex_counters", (Tcl_ObjCmdProc
*)test_read_mutex_counters
},
498 { "clear_mutex_counters", (Tcl_ObjCmdProc
*)test_clear_mutex_counters
},
501 for(i
=0; i
<sizeof(aCmd
)/sizeof(aCmd
[0]); i
++){
502 Tcl_CreateObjCommand(interp
, aCmd
[i
].zName
, aCmd
[i
].xProc
, 0, 0);
505 Tcl_LinkVar(interp
, "disable_mutex_init",
506 (char*)&g
.disableInit
, TCL_LINK_INT
);
507 Tcl_LinkVar(interp
, "disable_mutex_try",
508 (char*)&g
.disableTry
, TCL_LINK_INT
);