AryaWu/sqlite
0
1/*2** 2008 June 183**4** The author disclaims copyright to this source code. In place of5** 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#include "tclsqlite.h"15#include "sqlite3.h"16#include "sqliteInt.h"17#include <stdlib.h>18#include <assert.h>19#include <string.h>20 21#define MAX_MUTEXES (SQLITE_MUTEX_STATIC_VFS3+1)22#define STATIC_MUTEXES (MAX_MUTEXES-(SQLITE_MUTEX_RECURSIVE+1))23 24/* defined in main.c */25extern const char *sqlite3ErrName(int);26 27static const char *aName[MAX_MUTEXES+1] = {28 "fast", "recursive", "static_main", "static_mem",29 "static_open", "static_prng", "static_lru", "static_pmem",30 "static_app1", "static_app2", "static_app3", "static_vfs1",31 "static_vfs2", "static_vfs3", 032};33 34/* A countable mutex */35struct sqlite3_mutex {36 sqlite3_mutex *pReal;37 int eType;38};39 40/* State variables */41static struct test_mutex_globals {42 int isInstalled; /* True if installed */43 int disableInit; /* True to cause sqlite3_initialize() to fail */44 int disableTry; /* True to force sqlite3_mutex_try() to fail */45 int isInit; /* True if initialized */46 sqlite3_mutex_methods m; /* Interface to "real" mutex system */47 int aCounter[MAX_MUTEXES]; /* Number of grabs of each type of mutex */48 sqlite3_mutex aStatic[STATIC_MUTEXES]; /* The static mutexes */49} g = {0};50 51/* Return true if the countable mutex is currently held */52static int counterMutexHeld(sqlite3_mutex *p){53 return g.m.xMutexHeld(p->pReal);54}55 56/* Return true if the countable mutex is not currently held */57static int counterMutexNotheld(sqlite3_mutex *p){58 return g.m.xMutexNotheld(p->pReal);59}60 61/* Initialize the countable mutex interface62** Or, if g.disableInit is non-zero, then do not initialize but instead63** return the value of g.disableInit as the result code. This can be used64** to simulate an initialization failure.65*/66static int counterMutexInit(void){ 67 int rc;68 if( g.disableInit ) return g.disableInit;69 rc = g.m.xMutexInit();70 g.isInit = 1;71 return rc;72}73 74/*75** Uninitialize the mutex subsystem76*/77static int counterMutexEnd(void){ 78 g.isInit = 0;79 return g.m.xMutexEnd();80}81 82/*83** Allocate a countable mutex84*/85static sqlite3_mutex *counterMutexAlloc(int eType){86 sqlite3_mutex *pReal;87 sqlite3_mutex *pRet = 0;88 89 assert( g.isInit );90 assert( eType>=SQLITE_MUTEX_FAST );91 assert( eType<=SQLITE_MUTEX_STATIC_VFS3 );92 93 pReal = g.m.xMutexAlloc(eType);94 if( !pReal ) return 0;95 96 if( eType==SQLITE_MUTEX_FAST || eType==SQLITE_MUTEX_RECURSIVE ){97 pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex));98 }else{99 int eStaticType = eType - (MAX_MUTEXES - STATIC_MUTEXES);100 assert( eStaticType>=0 );101 assert( eStaticType<STATIC_MUTEXES );102 pRet = &g.aStatic[eStaticType];103 }104 105 pRet->eType = eType;106 pRet->pReal = pReal;107 return pRet;108}109 110/*111** Free a countable mutex112*/113static void counterMutexFree(sqlite3_mutex *p){114 assert( g.isInit );115 g.m.xMutexFree(p->pReal);116 if( p->eType==SQLITE_MUTEX_FAST || p->eType==SQLITE_MUTEX_RECURSIVE ){117 free(p);118 }119}120 121/*122** Enter a countable mutex. Block until entry is safe.123*/124static void counterMutexEnter(sqlite3_mutex *p){125 assert( g.isInit );126 assert( p->eType>=0 );127 assert( p->eType<MAX_MUTEXES );128 g.aCounter[p->eType]++;129 g.m.xMutexEnter(p->pReal);130}131 132/*133** Try to enter a mutex. Return true on success.134*/135static int counterMutexTry(sqlite3_mutex *p){136 assert( g.isInit );137 assert( p->eType>=0 );138 assert( p->eType<MAX_MUTEXES );139 g.aCounter[p->eType]++;140 if( g.disableTry ) return SQLITE_BUSY;141 return g.m.xMutexTry(p->pReal);142}143 144/* Leave a mutex145*/146static void counterMutexLeave(sqlite3_mutex *p){147 assert( g.isInit );148 g.m.xMutexLeave(p->pReal);149}150 151/*152** sqlite3_shutdown153*/154static int SQLITE_TCLAPI test_shutdown(155 void * clientData,156 Tcl_Interp *interp,157 int objc,158 Tcl_Obj *CONST objv[]159){160 int rc;161 162 if( objc!=1 ){163 Tcl_WrongNumArgs(interp, 1, objv, "");164 return TCL_ERROR;165 }166 167 rc = sqlite3_shutdown();168 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);169 return TCL_OK;170}171 172/*173** sqlite3_initialize174*/175static int SQLITE_TCLAPI test_initialize(176 void * clientData,177 Tcl_Interp *interp,178 int objc,179 Tcl_Obj *CONST objv[]180){181 int rc;182 183 if( objc!=1 ){184 Tcl_WrongNumArgs(interp, 1, objv, "");185 return TCL_ERROR;186 }187 188 rc = sqlite3_initialize();189 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);190 return TCL_OK;191}192 193/*194** install_mutex_counters BOOLEAN195*/196static int SQLITE_TCLAPI test_install_mutex_counters(197 void * clientData,198 Tcl_Interp *interp,199 int objc,200 Tcl_Obj *CONST objv[]201){202 int rc = SQLITE_OK;203 int isInstall;204 205 sqlite3_mutex_methods counter_methods = {206 counterMutexInit,207 counterMutexEnd,208 counterMutexAlloc,209 counterMutexFree,210 counterMutexEnter,211 counterMutexTry,212 counterMutexLeave,213 counterMutexHeld,214 counterMutexNotheld215 };216 217 if( objc!=2 ){218 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");219 return TCL_ERROR;220 }221 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){222 return TCL_ERROR;223 }224 225 assert(isInstall==0 || isInstall==1);226 assert(g.isInstalled==0 || g.isInstalled==1);227 if( isInstall==g.isInstalled ){228 Tcl_AppendResult(interp, "mutex counters are ", NULL);229 Tcl_AppendResult(interp, isInstall?"already installed":"not installed", NULL);230 return TCL_ERROR;231 }232 233 if( isInstall ){234 assert( g.m.xMutexAlloc==0 );235 rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m);236 if( rc==SQLITE_OK ){237 sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods);238 }239 g.disableTry = 0;240 }else{241 assert( g.m.xMutexAlloc );242 rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m);243 memset(&g.m, 0, sizeof(sqlite3_mutex_methods));244 }245 246 if( rc==SQLITE_OK ){247 g.isInstalled = isInstall;248 }249 250 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);251 return TCL_OK;252}253 254/*255** read_mutex_counters256*/257static int SQLITE_TCLAPI test_read_mutex_counters(258 void * clientData,259 Tcl_Interp *interp,260 int objc,261 Tcl_Obj *CONST objv[]262){263 Tcl_Obj *pRet;264 int ii;265 266 if( objc!=1 ){267 Tcl_WrongNumArgs(interp, 1, objv, "");268 return TCL_ERROR;269 }270 271 pRet = Tcl_NewObj();272 Tcl_IncrRefCount(pRet);273 for(ii=0; ii<MAX_MUTEXES; ii++){274 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1));275 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii]));276 }277 Tcl_SetObjResult(interp, pRet);278 Tcl_DecrRefCount(pRet);279 280 return TCL_OK;281}282 283/*284** clear_mutex_counters285*/286static int SQLITE_TCLAPI test_clear_mutex_counters(287 void * clientData,288 Tcl_Interp *interp,289 int objc,290 Tcl_Obj *CONST objv[]291){292 int ii;293 294 if( objc!=1 ){295 Tcl_WrongNumArgs(interp, 1, objv, "");296 return TCL_ERROR;297 }298 299 for(ii=0; ii<MAX_MUTEXES; ii++){300 g.aCounter[ii] = 0;301 }302 return TCL_OK;303}304 305/*306** Create and free a mutex. Return the mutex pointer. The pointer307** will be invalid since the mutex has already been freed. The308** return pointer just checks to see if the mutex really was allocated.309*/310static int SQLITE_TCLAPI test_alloc_mutex(311 void * clientData,312 Tcl_Interp *interp,313 int objc,314 Tcl_Obj *CONST objv[]315){316#if SQLITE_THREADSAFE317 sqlite3_mutex *p = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);318 char zBuf[100];319 sqlite3_mutex_free(p);320 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p);321 Tcl_AppendResult(interp, zBuf, (char*)0);322#endif323 return TCL_OK;324}325 326/*327** sqlite3_config OPTION328**329** OPTION can be either one of the keywords:330**331** SQLITE_CONFIG_SINGLETHREAD332** SQLITE_CONFIG_MULTITHREAD333** SQLITE_CONFIG_SERIALIZED334**335** Or OPTION can be an raw integer.336*/337static int SQLITE_TCLAPI test_config(338 void * clientData,339 Tcl_Interp *interp,340 int objc,341 Tcl_Obj *CONST objv[]342){343 struct ConfigOption {344 const char *zName;345 int iValue;346 } aOpt[] = {347 {"singlethread", SQLITE_CONFIG_SINGLETHREAD},348 {"multithread", SQLITE_CONFIG_MULTITHREAD},349 {"serialized", SQLITE_CONFIG_SERIALIZED},350 {0, 0}351 };352 int s = sizeof(struct ConfigOption);353 int i;354 int rc;355 356 if( objc!=2 ){357 Tcl_WrongNumArgs(interp, 1, objv, "");358 return TCL_ERROR;359 }360 361 if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){362 if( Tcl_GetIntFromObj(interp, objv[1], &i) ){363 return TCL_ERROR;364 }365 }else{366 i = aOpt[i].iValue;367 }368 369 rc = sqlite3_config(i);370 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);371 return TCL_OK;372}373 374static sqlite3 *getDbPointer(Tcl_Interp *pInterp, Tcl_Obj *pObj){375 sqlite3 *db;376 Tcl_CmdInfo info;377 char *zCmd = Tcl_GetString(pObj);378 if( Tcl_GetCommandInfo(pInterp, zCmd, &info) ){379 db = *((sqlite3 **)info.objClientData);380 }else{381 db = (sqlite3*)sqlite3TestTextToPtr(zCmd);382 }383 assert( db );384 return db;385}386 387static sqlite3_mutex *getStaticMutexPointer(388 Tcl_Interp *pInterp,389 Tcl_Obj *pObj390){391 int iMutex;392 if( Tcl_GetIndexFromObj(pInterp, pObj, aName, "mutex name", 0, &iMutex) ){393 return 0;394 }395 assert( iMutex!=SQLITE_MUTEX_FAST && iMutex!=SQLITE_MUTEX_RECURSIVE );396 return counterMutexAlloc(iMutex);397}398 399static int SQLITE_TCLAPI test_enter_static_mutex(400 void * clientData,401 Tcl_Interp *interp,402 int objc,403 Tcl_Obj *CONST objv[]404){405 sqlite3_mutex *pMutex;406 if( objc!=2 ){407 Tcl_WrongNumArgs(interp, 1, objv, "NAME");408 return TCL_ERROR;409 }410 pMutex = getStaticMutexPointer(interp, objv[1]);411 if( !pMutex ){412 return TCL_ERROR;413 }414 sqlite3_mutex_enter(pMutex);415 return TCL_OK;416}417 418static int SQLITE_TCLAPI test_leave_static_mutex(419 void * clientData,420 Tcl_Interp *interp,421 int objc,422 Tcl_Obj *CONST objv[]423){424 sqlite3_mutex *pMutex;425 if( objc!=2 ){426 Tcl_WrongNumArgs(interp, 1, objv, "NAME");427 return TCL_ERROR;428 }429 pMutex = getStaticMutexPointer(interp, objv[1]);430 if( !pMutex ){431 return TCL_ERROR;432 }433 sqlite3_mutex_leave(pMutex);434 return TCL_OK;435}436 437static int SQLITE_TCLAPI test_enter_db_mutex(438 void * clientData,439 Tcl_Interp *interp,440 int objc,441 Tcl_Obj *CONST objv[]442){443 sqlite3 *db;444 if( objc!=2 ){445 Tcl_WrongNumArgs(interp, 1, objv, "DB");446 return TCL_ERROR;447 }448 db = getDbPointer(interp, objv[1]);449 if( !db ){450 return TCL_ERROR;451 }452 sqlite3_mutex_enter(sqlite3_db_mutex(db));453 return TCL_OK;454}455 456static int SQLITE_TCLAPI test_leave_db_mutex(457 void * clientData,458 Tcl_Interp *interp,459 int objc,460 Tcl_Obj *CONST objv[]461){462 sqlite3 *db;463 if( objc!=2 ){464 Tcl_WrongNumArgs(interp, 1, objv, "DB");465 return TCL_ERROR;466 }467 db = getDbPointer(interp, objv[1]);468 if( !db ){469 return TCL_ERROR;470 }471 sqlite3_mutex_leave(sqlite3_db_mutex(db));472 return TCL_OK;473}474 475int Sqlitetest_mutex_Init(Tcl_Interp *interp){476 static struct {477 char *zName;478 Tcl_ObjCmdProc *xProc;479 } aCmd[] = {480 { "sqlite3_shutdown", (Tcl_ObjCmdProc*)test_shutdown },481 { "sqlite3_initialize", (Tcl_ObjCmdProc*)test_initialize },482 { "sqlite3_config", (Tcl_ObjCmdProc*)test_config },483 484 { "enter_static_mutex", (Tcl_ObjCmdProc*)test_enter_static_mutex },485 { "leave_static_mutex", (Tcl_ObjCmdProc*)test_leave_static_mutex },486 487 { "enter_db_mutex", (Tcl_ObjCmdProc*)test_enter_db_mutex },488 { "leave_db_mutex", (Tcl_ObjCmdProc*)test_leave_db_mutex },489 490 { "alloc_dealloc_mutex", (Tcl_ObjCmdProc*)test_alloc_mutex },491 { "install_mutex_counters", (Tcl_ObjCmdProc*)test_install_mutex_counters },492 { "read_mutex_counters", (Tcl_ObjCmdProc*)test_read_mutex_counters },493 { "clear_mutex_counters", (Tcl_ObjCmdProc*)test_clear_mutex_counters },494 };495 int i;496 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){497 Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);498 }499 500 Tcl_LinkVar(interp, "disable_mutex_init", 501 (char*)&g.disableInit, TCL_LINK_INT);502 Tcl_LinkVar(interp, "disable_mutex_try", 503 (char*)&g.disableTry, TCL_LINK_INT);504 return SQLITE_OK;505}506 