Add contributions section to README
[sqlcipher.git] / src / test_mutex.c
blobc9b4a29ab75c77ea5f36b5193256d70fe6580e95
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.
11 *************************************************************************
12 ** This file contains test logic for the sqlite3_mutex interfaces.
15 #include "tcl.h"
16 #include "sqlite3.h"
17 #include "sqliteInt.h"
18 #include <stdlib.h>
19 #include <assert.h>
20 #include <string.h>
22 /* defined in main.c */
23 extern const char *sqlite3ErrName(int);
25 /* A countable mutex */
26 struct sqlite3_mutex {
27 sqlite3_mutex *pReal;
28 int eType;
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};
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){
58 int rc;
59 if( g.disableInit ) return g.disableInit;
60 rc = g.m.xMutexInit();
61 g.isInit = 1;
62 return rc;
66 ** Uninitialize the mutex subsystem
68 static int counterMutexEnd(void){
69 g.isInit = 0;
70 return g.m.xMutexEnd();
74 ** Allocate a countable mutex
76 static sqlite3_mutex *counterMutexAlloc(int eType){
77 sqlite3_mutex *pReal;
78 sqlite3_mutex *pRet = 0;
80 assert( g.isInit );
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));
88 }else{
89 pRet = &g.aStatic[eType-2];
92 pRet->eType = eType;
93 pRet->pReal = pReal;
94 return pRet;
98 ** Free a countable mutex
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);
109 ** Enter a countable mutex. Block until entry is safe.
111 static void counterMutexEnter(sqlite3_mutex *p){
112 assert( g.isInit );
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){
121 assert( g.isInit );
122 g.aCounter[p->eType]++;
123 if( g.disableTry ) return SQLITE_BUSY;
124 return g.m.xMutexTry(p->pReal);
127 /* Leave a mutex
129 static void counterMutexLeave(sqlite3_mutex *p){
130 assert( g.isInit );
131 g.m.xMutexLeave(p->pReal);
135 ** sqlite3_shutdown
137 static int test_shutdown(
138 void * clientData,
139 Tcl_Interp *interp,
140 int objc,
141 Tcl_Obj *CONST objv[]
143 int rc;
145 if( objc!=1 ){
146 Tcl_WrongNumArgs(interp, 1, objv, "");
147 return TCL_ERROR;
150 rc = sqlite3_shutdown();
151 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
152 return TCL_OK;
156 ** sqlite3_initialize
158 static int test_initialize(
159 void * clientData,
160 Tcl_Interp *interp,
161 int objc,
162 Tcl_Obj *CONST objv[]
164 int rc;
166 if( objc!=1 ){
167 Tcl_WrongNumArgs(interp, 1, objv, "");
168 return TCL_ERROR;
171 rc = sqlite3_initialize();
172 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
173 return TCL_OK;
177 ** install_mutex_counters BOOLEAN
179 static int test_install_mutex_counters(
180 void * clientData,
181 Tcl_Interp *interp,
182 int objc,
183 Tcl_Obj *CONST objv[]
185 int rc = SQLITE_OK;
186 int isInstall;
188 sqlite3_mutex_methods counter_methods = {
189 counterMutexInit,
190 counterMutexEnd,
191 counterMutexAlloc,
192 counterMutexFree,
193 counterMutexEnter,
194 counterMutexTry,
195 counterMutexLeave,
196 counterMutexHeld,
197 counterMutexNotheld
200 if( objc!=2 ){
201 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
202 return TCL_ERROR;
204 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
205 return TCL_ERROR;
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;
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);
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));
229 if( rc==SQLITE_OK ){
230 g.isInstalled = isInstall;
233 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
234 return TCL_OK;
238 ** read_mutex_counters
240 static int test_read_mutex_counters(
241 void * clientData,
242 Tcl_Interp *interp,
243 int objc,
244 Tcl_Obj *CONST objv[]
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"
253 if( objc!=1 ){
254 Tcl_WrongNumArgs(interp, 1, objv, "");
255 return TCL_ERROR;
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]));
264 Tcl_SetObjResult(interp, pRet);
265 Tcl_DecrRefCount(pRet);
267 return TCL_OK;
271 ** clear_mutex_counters
273 static int test_clear_mutex_counters(
274 void * clientData,
275 Tcl_Interp *interp,
276 int objc,
277 Tcl_Obj *CONST objv[]
279 int ii;
281 if( objc!=1 ){
282 Tcl_WrongNumArgs(interp, 1, objv, "");
283 return TCL_ERROR;
286 for(ii=0; ii<8; ii++){
287 g.aCounter[ii] = 0;
289 return TCL_OK;
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(
298 void * clientData,
299 Tcl_Interp *interp,
300 int objc,
301 Tcl_Obj *CONST objv[]
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;
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(
325 void * clientData,
326 Tcl_Interp *interp,
327 int objc,
328 Tcl_Obj *CONST objv[]
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}
339 int s = sizeof(struct ConfigOption);
340 int i;
341 int rc;
343 if( objc!=2 ){
344 Tcl_WrongNumArgs(interp, 1, objv, "");
345 return TCL_ERROR;
348 if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){
349 if( Tcl_GetIntFromObj(interp, objv[1], &i) ){
350 return TCL_ERROR;
352 }else{
353 i = aOpt[i].iValue;
356 rc = sqlite3_config(i);
357 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
358 return TCL_OK;
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);
370 assert( db );
371 return db;
374 static int test_enter_db_mutex(
375 void * clientData,
376 Tcl_Interp *interp,
377 int objc,
378 Tcl_Obj *CONST objv[]
380 sqlite3 *db;
381 if( objc!=2 ){
382 Tcl_WrongNumArgs(interp, 1, objv, "DB");
383 return TCL_ERROR;
385 db = getDbPointer(interp, objv[1]);
386 if( !db ){
387 return TCL_ERROR;
389 sqlite3_mutex_enter(sqlite3_db_mutex(db));
390 return TCL_OK;
393 static int test_leave_db_mutex(
394 void * clientData,
395 Tcl_Interp *interp,
396 int objc,
397 Tcl_Obj *CONST objv[]
399 sqlite3 *db;
400 if( objc!=2 ){
401 Tcl_WrongNumArgs(interp, 1, objv, "DB");
402 return TCL_ERROR;
404 db = getDbPointer(interp, objv[1]);
405 if( !db ){
406 return TCL_ERROR;
408 sqlite3_mutex_leave(sqlite3_db_mutex(db));
409 return TCL_OK;
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 },
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 },
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);
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;