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. 10 ** 11 ************************************************************************* 12 ** 13 ** $Id: test_mutex.c,v 1.5 2008/07/08 00:06:50 drh Exp $ 14 */ 15 16 #include "tcl.h" 17 #include "sqlite3.h" 18 #include <stdlib.h> 19 #include <assert.h> 20 #include <string.h> 21 22 /* defined in test1.c */ 23 const char *sqlite3TestErrorName(int); 24 25 /* A countable mutex */ 26 struct sqlite3_mutex { 27 sqlite3_mutex *pReal; 28 int eType; 29 }; 30 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 isInit; /* True if initialized */ 36 sqlite3_mutex_methods m; /* Interface to "real" mutex system */ 37 int aCounter[8]; /* Number of grabs of each type of mutex */ 38 sqlite3_mutex aStatic[6]; /* The six static mutexes */ 39 } g; 40 41 /* Return true if the countable mutex is currently held */ 42 static int counterMutexHeld(sqlite3_mutex *p){ 43 return g.m.xMutexHeld(p->pReal); 44 } 45 46 /* Return true if the countable mutex is not currently held */ 47 static int counterMutexNotheld(sqlite3_mutex *p){ 48 return g.m.xMutexNotheld(p->pReal); 49 } 50 51 /* Initialize the countable mutex interface 52 ** Or, if g.disableInit is non-zero, then do not initialize but instead 53 ** return the value of g.disableInit as the result code. This can be used 54 ** to simulate an initialization failure. 55 */ 56 static int counterMutexInit(void){ 57 int rc; 58 if( g.disableInit ) return g.disableInit; 59 rc = g.m.xMutexInit(); 60 g.isInit = 1; 61 return rc; 62 } 63 64 /* 65 ** Uninitialize the mutex subsystem 66 */ 67 static int counterMutexEnd(void){ 68 assert( g.isInit ); 69 g.isInit = 0; 70 return g.m.xMutexEnd(); 71 } 72 73 /* 74 ** Allocate a countable mutex 75 */ 76 static sqlite3_mutex *counterMutexAlloc(int eType){ 77 sqlite3_mutex *pReal; 78 sqlite3_mutex *pRet = 0; 79 80 assert( g.isInit ); 81 assert(eType<8 && eType>=0); 82 83 pReal = g.m.xMutexAlloc(eType); 84 if( !pReal ) return 0; 85 86 if( eType==0 || eType==1 ){ 87 pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex)); 88 }else{ 89 pRet = &g.aStatic[eType-2]; 90 } 91 92 pRet->eType = eType; 93 pRet->pReal = pReal; 94 return pRet; 95 } 96 97 /* 98 ** Free a countable mutex 99 */ 100 static void counterMutexFree(sqlite3_mutex *p){ 101 assert( g.isInit ); 102 g.m.xMutexFree(p->pReal); 103 if( p->eType==0 || p->eType==1 ){ 104 free(p); 105 } 106 } 107 108 /* 109 ** Enter a countable mutex. Block until entry is safe. 110 */ 111 static void counterMutexEnter(sqlite3_mutex *p){ 112 assert( g.isInit ); 113 g.aCounter[p->eType]++; 114 g.m.xMutexEnter(p->pReal); 115 } 116 117 /* 118 ** Try to enter a mutex. Return true on success. 119 */ 120 static int counterMutexTry(sqlite3_mutex *p){ 121 assert( g.isInit ); 122 g.aCounter[p->eType]++; 123 return g.m.xMutexTry(p->pReal); 124 } 125 126 /* Leave a mutex 127 */ 128 static void counterMutexLeave(sqlite3_mutex *p){ 129 assert( g.isInit ); 130 g.m.xMutexLeave(p->pReal); 131 } 132 133 /* 134 ** sqlite3_shutdown 135 */ 136 static int test_shutdown( 137 void * clientData, 138 Tcl_Interp *interp, 139 int objc, 140 Tcl_Obj *CONST objv[] 141 ){ 142 int rc; 143 144 if( objc!=1 ){ 145 Tcl_WrongNumArgs(interp, 1, objv, ""); 146 return TCL_ERROR; 147 } 148 149 rc = sqlite3_shutdown(); 150 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 151 return TCL_OK; 152 } 153 154 /* 155 ** sqlite3_initialize 156 */ 157 static int test_initialize( 158 void * clientData, 159 Tcl_Interp *interp, 160 int objc, 161 Tcl_Obj *CONST objv[] 162 ){ 163 int rc; 164 165 if( objc!=1 ){ 166 Tcl_WrongNumArgs(interp, 1, objv, ""); 167 return TCL_ERROR; 168 } 169 170 rc = sqlite3_initialize(); 171 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 172 return TCL_OK; 173 } 174 175 /* 176 ** install_mutex_counters BOOLEAN 177 */ 178 static int test_install_mutex_counters( 179 void * clientData, 180 Tcl_Interp *interp, 181 int objc, 182 Tcl_Obj *CONST objv[] 183 ){ 184 int rc = SQLITE_OK; 185 int isInstall; 186 187 sqlite3_mutex_methods counter_methods = { 188 counterMutexInit, 189 counterMutexEnd, 190 counterMutexAlloc, 191 counterMutexFree, 192 counterMutexEnter, 193 counterMutexTry, 194 counterMutexLeave, 195 counterMutexHeld, 196 counterMutexNotheld 197 }; 198 199 if( objc!=2 ){ 200 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 201 return TCL_ERROR; 202 } 203 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ 204 return TCL_ERROR; 205 } 206 207 assert(isInstall==0 || isInstall==1); 208 assert(g.isInstalled==0 || g.isInstalled==1); 209 if( isInstall==g.isInstalled ){ 210 Tcl_AppendResult(interp, "mutex counters are ", 0); 211 Tcl_AppendResult(interp, isInstall?"already installed":"not installed", 0); 212 return TCL_ERROR; 213 } 214 215 if( isInstall ){ 216 assert( g.m.xMutexAlloc==0 ); 217 rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m); 218 if( rc==SQLITE_OK ){ 219 sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods); 220 } 221 }else{ 222 assert( g.m.xMutexAlloc ); 223 rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m); 224 memset(&g.m, 0, sizeof(sqlite3_mutex_methods)); 225 } 226 227 if( rc==SQLITE_OK ){ 228 g.isInstalled = isInstall; 229 } 230 231 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 232 return TCL_OK; 233 } 234 235 /* 236 ** read_mutex_counters 237 */ 238 static int test_read_mutex_counters( 239 void * clientData, 240 Tcl_Interp *interp, 241 int objc, 242 Tcl_Obj *CONST objv[] 243 ){ 244 Tcl_Obj *pRet; 245 int ii; 246 char *aName[8] = { 247 "fast", "recursive", "static_master", "static_mem", 248 "static_mem2", "static_prng", "static_lru", "static_lru2" 249 }; 250 251 if( objc!=1 ){ 252 Tcl_WrongNumArgs(interp, 1, objv, ""); 253 return TCL_ERROR; 254 } 255 256 pRet = Tcl_NewObj(); 257 Tcl_IncrRefCount(pRet); 258 for(ii=0; ii<8; ii++){ 259 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1)); 260 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii])); 261 } 262 Tcl_SetObjResult(interp, pRet); 263 Tcl_DecrRefCount(pRet); 264 265 return TCL_OK; 266 } 267 268 /* 269 ** clear_mutex_counters 270 */ 271 static int test_clear_mutex_counters( 272 void * clientData, 273 Tcl_Interp *interp, 274 int objc, 275 Tcl_Obj *CONST objv[] 276 ){ 277 int ii; 278 279 if( objc!=1 ){ 280 Tcl_WrongNumArgs(interp, 1, objv, ""); 281 return TCL_ERROR; 282 } 283 284 for(ii=0; ii<8; ii++){ 285 g.aCounter[ii] = 0; 286 } 287 return TCL_OK; 288 } 289 290 /* 291 ** sqlite3_config OPTION 292 */ 293 static int test_config( 294 void * clientData, 295 Tcl_Interp *interp, 296 int objc, 297 Tcl_Obj *CONST objv[] 298 ){ 299 struct ConfigOption { 300 const char *zName; 301 int iValue; 302 } aOpt[] = { 303 {"singlethread", SQLITE_CONFIG_SINGLETHREAD}, 304 {"multithread", SQLITE_CONFIG_MULTITHREAD}, 305 {"serialized", SQLITE_CONFIG_SERIALIZED}, 306 {0, 0} 307 }; 308 int s = sizeof(struct ConfigOption); 309 int i; 310 int rc; 311 312 if( objc!=2 ){ 313 Tcl_WrongNumArgs(interp, 1, objv, ""); 314 return TCL_ERROR; 315 } 316 317 if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){ 318 return TCL_ERROR; 319 } 320 321 rc = sqlite3_config(aOpt[i].iValue); 322 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 323 return TCL_OK; 324 } 325 326 int Sqlitetest_mutex_Init(Tcl_Interp *interp){ 327 static struct { 328 char *zName; 329 Tcl_ObjCmdProc *xProc; 330 } aCmd[] = { 331 { "sqlite3_shutdown", (Tcl_ObjCmdProc*)test_shutdown }, 332 { "sqlite3_initialize", (Tcl_ObjCmdProc*)test_initialize }, 333 { "sqlite3_config", (Tcl_ObjCmdProc*)test_config }, 334 335 { "install_mutex_counters", (Tcl_ObjCmdProc*)test_install_mutex_counters }, 336 { "read_mutex_counters", (Tcl_ObjCmdProc*)test_read_mutex_counters }, 337 { "clear_mutex_counters", (Tcl_ObjCmdProc*)test_clear_mutex_counters }, 338 }; 339 int i; 340 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 341 Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 342 } 343 memset(&g, 0, sizeof(g)); 344 345 Tcl_LinkVar(interp, "disable_mutex_init", 346 (char*)&g.disableInit, TCL_LINK_INT); 347 return SQLITE_OK; 348 } 349