| OLD | NEW |
| 1 /* | 1 /* |
| 2 ** 2008 June 18 | 2 ** 2008 June 18 |
| 3 ** | 3 ** |
| 4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
| 5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
| 6 ** | 6 ** |
| 7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
| 8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
| 9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
| 10 ** | 10 ** |
| 11 ************************************************************************* | 11 ************************************************************************* |
| 12 ** This file contains test logic for the sqlite3_mutex interfaces. | 12 ** This file contains test logic for the sqlite3_mutex interfaces. |
| 13 */ | 13 */ |
| 14 | 14 |
| 15 #include "tcl.h" | 15 #include "tcl.h" |
| 16 #include "sqlite3.h" | 16 #include "sqlite3.h" |
| 17 #include "sqliteInt.h" | 17 #include "sqliteInt.h" |
| 18 #include <stdlib.h> | 18 #include <stdlib.h> |
| 19 #include <assert.h> | 19 #include <assert.h> |
| 20 #include <string.h> | 20 #include <string.h> |
| 21 | 21 |
| 22 #define MAX_MUTEXES (SQLITE_MUTEX_STATIC_VFS3+1) |
| 23 #define STATIC_MUTEXES (MAX_MUTEXES-(SQLITE_MUTEX_RECURSIVE+1)) |
| 24 |
| 22 /* defined in main.c */ | 25 /* defined in main.c */ |
| 23 extern const char *sqlite3ErrName(int); | 26 extern const char *sqlite3ErrName(int); |
| 24 | 27 |
| 28 static const char *aName[MAX_MUTEXES+1] = { |
| 29 "fast", "recursive", "static_master", "static_mem", |
| 30 "static_open", "static_prng", "static_lru", "static_pmem", |
| 31 "static_app1", "static_app2", "static_app3", "static_vfs1", |
| 32 "static_vfs2", "static_vfs3", 0 |
| 33 }; |
| 34 |
| 25 /* A countable mutex */ | 35 /* A countable mutex */ |
| 26 struct sqlite3_mutex { | 36 struct sqlite3_mutex { |
| 27 sqlite3_mutex *pReal; | 37 sqlite3_mutex *pReal; |
| 28 int eType; | 38 int eType; |
| 29 }; | 39 }; |
| 30 | 40 |
| 31 /* State variables */ | 41 /* State variables */ |
| 32 static struct test_mutex_globals { | 42 static struct test_mutex_globals { |
| 33 int isInstalled; /* True if installed */ | 43 int isInstalled; /* True if installed */ |
| 34 int disableInit; /* True to cause sqlite3_initalize() to fail */ | 44 int disableInit; /* True to cause sqlite3_initalize() to fail */ |
| 35 int disableTry; /* True to force sqlite3_mutex_try() to fail */ | 45 int disableTry; /* True to force sqlite3_mutex_try() to fail */ |
| 36 int isInit; /* True if initialized */ | 46 int isInit; /* True if initialized */ |
| 37 sqlite3_mutex_methods m; /* Interface to "real" mutex system */ | 47 sqlite3_mutex_methods m; /* Interface to "real" mutex system */ |
| 38 int aCounter[8]; /* Number of grabs of each type of mutex */ | 48 int aCounter[MAX_MUTEXES]; /* Number of grabs of each type of mutex */ |
| 39 sqlite3_mutex aStatic[6]; /* The six static mutexes */ | 49 sqlite3_mutex aStatic[STATIC_MUTEXES]; /* The static mutexes */ |
| 40 } g = {0}; | 50 } g = {0}; |
| 41 | 51 |
| 42 /* Return true if the countable mutex is currently held */ | 52 /* Return true if the countable mutex is currently held */ |
| 43 static int counterMutexHeld(sqlite3_mutex *p){ | 53 static int counterMutexHeld(sqlite3_mutex *p){ |
| 44 return g.m.xMutexHeld(p->pReal); | 54 return g.m.xMutexHeld(p->pReal); |
| 45 } | 55 } |
| 46 | 56 |
| 47 /* Return true if the countable mutex is not currently held */ | 57 /* Return true if the countable mutex is not currently held */ |
| 48 static int counterMutexNotheld(sqlite3_mutex *p){ | 58 static int counterMutexNotheld(sqlite3_mutex *p){ |
| 49 return g.m.xMutexNotheld(p->pReal); | 59 return g.m.xMutexNotheld(p->pReal); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 71 } | 81 } |
| 72 | 82 |
| 73 /* | 83 /* |
| 74 ** Allocate a countable mutex | 84 ** Allocate a countable mutex |
| 75 */ | 85 */ |
| 76 static sqlite3_mutex *counterMutexAlloc(int eType){ | 86 static sqlite3_mutex *counterMutexAlloc(int eType){ |
| 77 sqlite3_mutex *pReal; | 87 sqlite3_mutex *pReal; |
| 78 sqlite3_mutex *pRet = 0; | 88 sqlite3_mutex *pRet = 0; |
| 79 | 89 |
| 80 assert( g.isInit ); | 90 assert( g.isInit ); |
| 81 assert(eType<8 && eType>=0); | 91 assert( eType>=SQLITE_MUTEX_FAST ); |
| 92 assert( eType<=SQLITE_MUTEX_STATIC_VFS3 ); |
| 82 | 93 |
| 83 pReal = g.m.xMutexAlloc(eType); | 94 pReal = g.m.xMutexAlloc(eType); |
| 84 if( !pReal ) return 0; | 95 if( !pReal ) return 0; |
| 85 | 96 |
| 86 if( eType==SQLITE_MUTEX_FAST || eType==SQLITE_MUTEX_RECURSIVE ){ | 97 if( eType==SQLITE_MUTEX_FAST || eType==SQLITE_MUTEX_RECURSIVE ){ |
| 87 pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex)); | 98 pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex)); |
| 88 }else{ | 99 }else{ |
| 89 pRet = &g.aStatic[eType-2]; | 100 int eStaticType = eType - (MAX_MUTEXES - STATIC_MUTEXES); |
| 101 assert( eStaticType>=0 ); |
| 102 assert( eStaticType<STATIC_MUTEXES ); |
| 103 pRet = &g.aStatic[eStaticType]; |
| 90 } | 104 } |
| 91 | 105 |
| 92 pRet->eType = eType; | 106 pRet->eType = eType; |
| 93 pRet->pReal = pReal; | 107 pRet->pReal = pReal; |
| 94 return pRet; | 108 return pRet; |
| 95 } | 109 } |
| 96 | 110 |
| 97 /* | 111 /* |
| 98 ** Free a countable mutex | 112 ** Free a countable mutex |
| 99 */ | 113 */ |
| 100 static void counterMutexFree(sqlite3_mutex *p){ | 114 static void counterMutexFree(sqlite3_mutex *p){ |
| 101 assert( g.isInit ); | 115 assert( g.isInit ); |
| 102 g.m.xMutexFree(p->pReal); | 116 g.m.xMutexFree(p->pReal); |
| 103 if( p->eType==SQLITE_MUTEX_FAST || p->eType==SQLITE_MUTEX_RECURSIVE ){ | 117 if( p->eType==SQLITE_MUTEX_FAST || p->eType==SQLITE_MUTEX_RECURSIVE ){ |
| 104 free(p); | 118 free(p); |
| 105 } | 119 } |
| 106 } | 120 } |
| 107 | 121 |
| 108 /* | 122 /* |
| 109 ** Enter a countable mutex. Block until entry is safe. | 123 ** Enter a countable mutex. Block until entry is safe. |
| 110 */ | 124 */ |
| 111 static void counterMutexEnter(sqlite3_mutex *p){ | 125 static void counterMutexEnter(sqlite3_mutex *p){ |
| 112 assert( g.isInit ); | 126 assert( g.isInit ); |
| 127 assert( p->eType>=0 ); |
| 128 assert( p->eType<MAX_MUTEXES ); |
| 113 g.aCounter[p->eType]++; | 129 g.aCounter[p->eType]++; |
| 114 g.m.xMutexEnter(p->pReal); | 130 g.m.xMutexEnter(p->pReal); |
| 115 } | 131 } |
| 116 | 132 |
| 117 /* | 133 /* |
| 118 ** Try to enter a mutex. Return true on success. | 134 ** Try to enter a mutex. Return true on success. |
| 119 */ | 135 */ |
| 120 static int counterMutexTry(sqlite3_mutex *p){ | 136 static int counterMutexTry(sqlite3_mutex *p){ |
| 121 assert( g.isInit ); | 137 assert( g.isInit ); |
| 138 assert( p->eType>=0 ); |
| 139 assert( p->eType<MAX_MUTEXES ); |
| 122 g.aCounter[p->eType]++; | 140 g.aCounter[p->eType]++; |
| 123 if( g.disableTry ) return SQLITE_BUSY; | 141 if( g.disableTry ) return SQLITE_BUSY; |
| 124 return g.m.xMutexTry(p->pReal); | 142 return g.m.xMutexTry(p->pReal); |
| 125 } | 143 } |
| 126 | 144 |
| 127 /* Leave a mutex | 145 /* Leave a mutex |
| 128 */ | 146 */ |
| 129 static void counterMutexLeave(sqlite3_mutex *p){ | 147 static void counterMutexLeave(sqlite3_mutex *p){ |
| 130 assert( g.isInit ); | 148 assert( g.isInit ); |
| 131 g.m.xMutexLeave(p->pReal); | 149 g.m.xMutexLeave(p->pReal); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 ** read_mutex_counters | 256 ** read_mutex_counters |
| 239 */ | 257 */ |
| 240 static int test_read_mutex_counters( | 258 static int test_read_mutex_counters( |
| 241 void * clientData, | 259 void * clientData, |
| 242 Tcl_Interp *interp, | 260 Tcl_Interp *interp, |
| 243 int objc, | 261 int objc, |
| 244 Tcl_Obj *CONST objv[] | 262 Tcl_Obj *CONST objv[] |
| 245 ){ | 263 ){ |
| 246 Tcl_Obj *pRet; | 264 Tcl_Obj *pRet; |
| 247 int ii; | 265 int ii; |
| 248 char *aName[8] = { | |
| 249 "fast", "recursive", "static_master", "static_mem", | |
| 250 "static_open", "static_prng", "static_lru", "static_pmem" | |
| 251 }; | |
| 252 | 266 |
| 253 if( objc!=1 ){ | 267 if( objc!=1 ){ |
| 254 Tcl_WrongNumArgs(interp, 1, objv, ""); | 268 Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 255 return TCL_ERROR; | 269 return TCL_ERROR; |
| 256 } | 270 } |
| 257 | 271 |
| 258 pRet = Tcl_NewObj(); | 272 pRet = Tcl_NewObj(); |
| 259 Tcl_IncrRefCount(pRet); | 273 Tcl_IncrRefCount(pRet); |
| 260 for(ii=0; ii<8; ii++){ | 274 for(ii=0; ii<MAX_MUTEXES; ii++){ |
| 261 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1)); | 275 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1)); |
| 262 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii])); | 276 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii])); |
| 263 } | 277 } |
| 264 Tcl_SetObjResult(interp, pRet); | 278 Tcl_SetObjResult(interp, pRet); |
| 265 Tcl_DecrRefCount(pRet); | 279 Tcl_DecrRefCount(pRet); |
| 266 | 280 |
| 267 return TCL_OK; | 281 return TCL_OK; |
| 268 } | 282 } |
| 269 | 283 |
| 270 /* | 284 /* |
| 271 ** clear_mutex_counters | 285 ** clear_mutex_counters |
| 272 */ | 286 */ |
| 273 static int test_clear_mutex_counters( | 287 static int test_clear_mutex_counters( |
| 274 void * clientData, | 288 void * clientData, |
| 275 Tcl_Interp *interp, | 289 Tcl_Interp *interp, |
| 276 int objc, | 290 int objc, |
| 277 Tcl_Obj *CONST objv[] | 291 Tcl_Obj *CONST objv[] |
| 278 ){ | 292 ){ |
| 279 int ii; | 293 int ii; |
| 280 | 294 |
| 281 if( objc!=1 ){ | 295 if( objc!=1 ){ |
| 282 Tcl_WrongNumArgs(interp, 1, objv, ""); | 296 Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 283 return TCL_ERROR; | 297 return TCL_ERROR; |
| 284 } | 298 } |
| 285 | 299 |
| 286 for(ii=0; ii<8; ii++){ | 300 for(ii=0; ii<MAX_MUTEXES; ii++){ |
| 287 g.aCounter[ii] = 0; | 301 g.aCounter[ii] = 0; |
| 288 } | 302 } |
| 289 return TCL_OK; | 303 return TCL_OK; |
| 290 } | 304 } |
| 291 | 305 |
| 292 /* | 306 /* |
| 293 ** Create and free a mutex. Return the mutex pointer. The pointer | 307 ** Create and free a mutex. Return the mutex pointer. The pointer |
| 294 ** will be invalid since the mutex has already been freed. The | 308 ** will be invalid since the mutex has already been freed. The |
| 295 ** return pointer just checks to see if the mutex really was allocated. | 309 ** return pointer just checks to see if the mutex really was allocated. |
| 296 */ | 310 */ |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 char *zCmd = Tcl_GetString(pObj); | 378 char *zCmd = Tcl_GetString(pObj); |
| 365 if( Tcl_GetCommandInfo(pInterp, zCmd, &info) ){ | 379 if( Tcl_GetCommandInfo(pInterp, zCmd, &info) ){ |
| 366 db = *((sqlite3 **)info.objClientData); | 380 db = *((sqlite3 **)info.objClientData); |
| 367 }else{ | 381 }else{ |
| 368 db = (sqlite3*)sqlite3TestTextToPtr(zCmd); | 382 db = (sqlite3*)sqlite3TestTextToPtr(zCmd); |
| 369 } | 383 } |
| 370 assert( db ); | 384 assert( db ); |
| 371 return db; | 385 return db; |
| 372 } | 386 } |
| 373 | 387 |
| 388 static sqlite3_mutex *getStaticMutexPointer( |
| 389 Tcl_Interp *pInterp, |
| 390 Tcl_Obj *pObj |
| 391 ){ |
| 392 int iMutex; |
| 393 if( Tcl_GetIndexFromObj(pInterp, pObj, aName, "mutex name", 0, &iMutex) ){ |
| 394 return 0; |
| 395 } |
| 396 assert( iMutex!=SQLITE_MUTEX_FAST && iMutex!=SQLITE_MUTEX_RECURSIVE ); |
| 397 return counterMutexAlloc(iMutex); |
| 398 } |
| 399 |
| 400 static int test_enter_static_mutex( |
| 401 void * clientData, |
| 402 Tcl_Interp *interp, |
| 403 int objc, |
| 404 Tcl_Obj *CONST objv[] |
| 405 ){ |
| 406 sqlite3_mutex *pMutex; |
| 407 if( objc!=2 ){ |
| 408 Tcl_WrongNumArgs(interp, 1, objv, "NAME"); |
| 409 return TCL_ERROR; |
| 410 } |
| 411 pMutex = getStaticMutexPointer(interp, objv[1]); |
| 412 if( !pMutex ){ |
| 413 return TCL_ERROR; |
| 414 } |
| 415 sqlite3_mutex_enter(pMutex); |
| 416 return TCL_OK; |
| 417 } |
| 418 |
| 419 static int test_leave_static_mutex( |
| 420 void * clientData, |
| 421 Tcl_Interp *interp, |
| 422 int objc, |
| 423 Tcl_Obj *CONST objv[] |
| 424 ){ |
| 425 sqlite3_mutex *pMutex; |
| 426 if( objc!=2 ){ |
| 427 Tcl_WrongNumArgs(interp, 1, objv, "NAME"); |
| 428 return TCL_ERROR; |
| 429 } |
| 430 pMutex = getStaticMutexPointer(interp, objv[1]); |
| 431 if( !pMutex ){ |
| 432 return TCL_ERROR; |
| 433 } |
| 434 sqlite3_mutex_leave(pMutex); |
| 435 return TCL_OK; |
| 436 } |
| 437 |
| 374 static int test_enter_db_mutex( | 438 static int test_enter_db_mutex( |
| 375 void * clientData, | 439 void * clientData, |
| 376 Tcl_Interp *interp, | 440 Tcl_Interp *interp, |
| 377 int objc, | 441 int objc, |
| 378 Tcl_Obj *CONST objv[] | 442 Tcl_Obj *CONST objv[] |
| 379 ){ | 443 ){ |
| 380 sqlite3 *db; | 444 sqlite3 *db; |
| 381 if( objc!=2 ){ | 445 if( objc!=2 ){ |
| 382 Tcl_WrongNumArgs(interp, 1, objv, "DB"); | 446 Tcl_WrongNumArgs(interp, 1, objv, "DB"); |
| 383 return TCL_ERROR; | 447 return TCL_ERROR; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 411 | 475 |
| 412 int Sqlitetest_mutex_Init(Tcl_Interp *interp){ | 476 int Sqlitetest_mutex_Init(Tcl_Interp *interp){ |
| 413 static struct { | 477 static struct { |
| 414 char *zName; | 478 char *zName; |
| 415 Tcl_ObjCmdProc *xProc; | 479 Tcl_ObjCmdProc *xProc; |
| 416 } aCmd[] = { | 480 } aCmd[] = { |
| 417 { "sqlite3_shutdown", (Tcl_ObjCmdProc*)test_shutdown }, | 481 { "sqlite3_shutdown", (Tcl_ObjCmdProc*)test_shutdown }, |
| 418 { "sqlite3_initialize", (Tcl_ObjCmdProc*)test_initialize }, | 482 { "sqlite3_initialize", (Tcl_ObjCmdProc*)test_initialize }, |
| 419 { "sqlite3_config", (Tcl_ObjCmdProc*)test_config }, | 483 { "sqlite3_config", (Tcl_ObjCmdProc*)test_config }, |
| 420 | 484 |
| 485 { "enter_static_mutex", (Tcl_ObjCmdProc*)test_enter_static_mutex }, |
| 486 { "leave_static_mutex", (Tcl_ObjCmdProc*)test_leave_static_mutex }, |
| 487 |
| 421 { "enter_db_mutex", (Tcl_ObjCmdProc*)test_enter_db_mutex }, | 488 { "enter_db_mutex", (Tcl_ObjCmdProc*)test_enter_db_mutex }, |
| 422 { "leave_db_mutex", (Tcl_ObjCmdProc*)test_leave_db_mutex }, | 489 { "leave_db_mutex", (Tcl_ObjCmdProc*)test_leave_db_mutex }, |
| 423 | 490 |
| 424 { "alloc_dealloc_mutex", (Tcl_ObjCmdProc*)test_alloc_mutex }, | 491 { "alloc_dealloc_mutex", (Tcl_ObjCmdProc*)test_alloc_mutex }, |
| 425 { "install_mutex_counters", (Tcl_ObjCmdProc*)test_install_mutex_counters }, | 492 { "install_mutex_counters", (Tcl_ObjCmdProc*)test_install_mutex_counters }, |
| 426 { "read_mutex_counters", (Tcl_ObjCmdProc*)test_read_mutex_counters }, | 493 { "read_mutex_counters", (Tcl_ObjCmdProc*)test_read_mutex_counters }, |
| 427 { "clear_mutex_counters", (Tcl_ObjCmdProc*)test_clear_mutex_counters }, | 494 { "clear_mutex_counters", (Tcl_ObjCmdProc*)test_clear_mutex_counters }, |
| 428 }; | 495 }; |
| 429 int i; | 496 int i; |
| 430 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ | 497 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ |
| 431 Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); | 498 Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); |
| 432 } | 499 } |
| 433 | 500 |
| 434 Tcl_LinkVar(interp, "disable_mutex_init", | 501 Tcl_LinkVar(interp, "disable_mutex_init", |
| 435 (char*)&g.disableInit, TCL_LINK_INT); | 502 (char*)&g.disableInit, TCL_LINK_INT); |
| 436 Tcl_LinkVar(interp, "disable_mutex_try", | 503 Tcl_LinkVar(interp, "disable_mutex_try", |
| 437 (char*)&g.disableTry, TCL_LINK_INT); | 504 (char*)&g.disableTry, TCL_LINK_INT); |
| 438 return SQLITE_OK; | 505 return SQLITE_OK; |
| 439 } | 506 } |
| OLD | NEW |