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.2 2008/06/18 17:09:10 danielk1977 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 const char *sqlite3TestErrorName(int); 23 24 struct sqlite3_mutex { 25 sqlite3_mutex *pReal; 26 int eType; 27 }; 28 29 static struct test_mutex_globals { 30 int isInstalled; 31 sqlite3_mutex_methods m; /* Interface to "real" mutex system */ 32 int aCounter[8]; /* Number of grabs of each type of mutex */ 33 sqlite3_mutex aStatic[6]; /* The six static mutexes */ 34 } g; 35 36 static int counterMutexHeld(sqlite3_mutex *p){ 37 return g.m.xMutexHeld(p->pReal); 38 } 39 40 static int counterMutexNotheld(sqlite3_mutex *p){ 41 return g.m.xMutexNotheld(p->pReal); 42 } 43 44 static int counterMutexInit(void){ 45 return g.m.xMutexInit(); 46 } 47 48 static int counterMutexEnd(void){ 49 return g.m.xMutexEnd(); 50 } 51 52 static sqlite3_mutex *counterMutexAlloc(int eType){ 53 sqlite3_mutex *pReal; 54 sqlite3_mutex *pRet = 0; 55 56 assert(eType<8 && eType>=0); 57 58 pReal = g.m.xMutexAlloc(eType); 59 if( !pReal ) return 0; 60 61 if( eType==0 || eType==1 ){ 62 pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex)); 63 }else{ 64 pRet = &g.aStatic[eType-2]; 65 } 66 67 pRet->eType = eType; 68 pRet->pReal = pReal; 69 return pRet; 70 } 71 72 static void counterMutexFree(sqlite3_mutex *p){ 73 g.m.xMutexFree(p->pReal); 74 if( p->eType==0 || p->eType==1 ){ 75 free(p); 76 } 77 } 78 79 static void counterMutexEnter(sqlite3_mutex *p){ 80 g.aCounter[p->eType]++; 81 g.m.xMutexEnter(p->pReal); 82 } 83 84 static int counterMutexTry(sqlite3_mutex *p){ 85 g.aCounter[p->eType]++; 86 return g.m.xMutexTry(p->pReal); 87 } 88 89 static void counterMutexLeave(sqlite3_mutex *p){ 90 g.m.xMutexLeave(p->pReal); 91 } 92 93 /* 94 ** sqlite3_shutdown 95 */ 96 static int test_shutdown( 97 void * clientData, 98 Tcl_Interp *interp, 99 int objc, 100 Tcl_Obj *CONST objv[] 101 ){ 102 int rc; 103 104 if( objc!=1 ){ 105 Tcl_WrongNumArgs(interp, 1, objv, ""); 106 return TCL_ERROR; 107 } 108 109 rc = sqlite3_shutdown(); 110 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 111 return TCL_OK; 112 } 113 114 /* 115 ** sqlite3_initialize 116 */ 117 static int test_initialize( 118 void * clientData, 119 Tcl_Interp *interp, 120 int objc, 121 Tcl_Obj *CONST objv[] 122 ){ 123 int rc; 124 125 if( objc!=1 ){ 126 Tcl_WrongNumArgs(interp, 1, objv, ""); 127 return TCL_ERROR; 128 } 129 130 rc = sqlite3_initialize(); 131 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 132 return TCL_OK; 133 } 134 135 /* 136 ** install_mutex_counters BOOLEAN 137 */ 138 static int test_install_mutex_counters( 139 void * clientData, 140 Tcl_Interp *interp, 141 int objc, 142 Tcl_Obj *CONST objv[] 143 ){ 144 int rc = SQLITE_OK; 145 int isInstall; 146 147 sqlite3_mutex_methods counter_methods = { 148 counterMutexInit, 149 counterMutexAlloc, 150 counterMutexFree, 151 counterMutexEnter, 152 counterMutexTry, 153 counterMutexLeave, 154 counterMutexEnd, 155 counterMutexHeld, 156 counterMutexNotheld 157 }; 158 159 if( objc!=2 ){ 160 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 161 return TCL_ERROR; 162 } 163 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ 164 return TCL_ERROR; 165 } 166 167 assert(isInstall==0 || isInstall==1); 168 assert(g.isInstalled==0 || g.isInstalled==1); 169 if( isInstall==g.isInstalled ){ 170 Tcl_AppendResult(interp, "mutex counters are ", 0); 171 Tcl_AppendResult(interp, isInstall?"already installed":"not installed", 0); 172 return TCL_ERROR; 173 } 174 175 if( isInstall ){ 176 assert( g.m.xMutexAlloc==0 ); 177 rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m); 178 if( rc==SQLITE_OK ){ 179 sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods); 180 } 181 }else{ 182 assert( g.m.xMutexAlloc ); 183 rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m); 184 memset(&g.m, 0, sizeof(sqlite3_mutex_methods)); 185 } 186 187 if( rc==SQLITE_OK ){ 188 g.isInstalled = isInstall; 189 } 190 191 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 192 return TCL_OK; 193 } 194 195 /* 196 ** read_mutex_counters 197 */ 198 static int test_read_mutex_counters( 199 void * clientData, 200 Tcl_Interp *interp, 201 int objc, 202 Tcl_Obj *CONST objv[] 203 ){ 204 Tcl_Obj *pRet; 205 int ii; 206 char *aName[8] = { 207 "fast", "recursive", "static_master", "static_mem", 208 "static_mem2", "static_prng", "static_lru", "static_lru2" 209 }; 210 211 if( objc!=1 ){ 212 Tcl_WrongNumArgs(interp, 1, objv, ""); 213 return TCL_ERROR; 214 } 215 216 pRet = Tcl_NewObj(); 217 Tcl_IncrRefCount(pRet); 218 for(ii=0; ii<8; ii++){ 219 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1)); 220 Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii])); 221 } 222 Tcl_SetObjResult(interp, pRet); 223 Tcl_DecrRefCount(pRet); 224 225 return TCL_OK; 226 } 227 228 /* 229 ** clear_mutex_counters 230 */ 231 static int test_clear_mutex_counters( 232 void * clientData, 233 Tcl_Interp *interp, 234 int objc, 235 Tcl_Obj *CONST objv[] 236 ){ 237 int ii; 238 239 if( objc!=1 ){ 240 Tcl_WrongNumArgs(interp, 1, objv, ""); 241 return TCL_ERROR; 242 } 243 244 for(ii=0; ii<8; ii++){ 245 g.aCounter[ii] = 0; 246 } 247 return TCL_OK; 248 } 249 250 /* 251 ** sqlite3_config OPTION 252 */ 253 static int test_config( 254 void * clientData, 255 Tcl_Interp *interp, 256 int objc, 257 Tcl_Obj *CONST objv[] 258 ){ 259 struct ConfigOption { 260 const char *zName; 261 int iValue; 262 } aOpt[] = { 263 {"singlethread", SQLITE_CONFIG_SINGLETHREAD}, 264 {"multithread", SQLITE_CONFIG_MULTITHREAD}, 265 {"serialized", SQLITE_CONFIG_SERIALIZED}, 266 {0, 0} 267 }; 268 int s = sizeof(struct ConfigOption); 269 int i; 270 int rc; 271 272 if( objc!=2 ){ 273 Tcl_WrongNumArgs(interp, 1, objv, ""); 274 return TCL_ERROR; 275 } 276 277 if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){ 278 return TCL_ERROR; 279 } 280 281 rc = sqlite3_config(aOpt[i].iValue); 282 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 283 return TCL_OK; 284 } 285 286 int Sqlitetest_mutex_Init(Tcl_Interp *interp){ 287 static struct { 288 char *zName; 289 Tcl_ObjCmdProc *xProc; 290 } aCmd[] = { 291 { "sqlite3_shutdown", (Tcl_ObjCmdProc*)test_shutdown }, 292 { "sqlite3_initialize", (Tcl_ObjCmdProc*)test_initialize }, 293 { "sqlite3_config", (Tcl_ObjCmdProc*)test_config }, 294 295 { "install_mutex_counters", (Tcl_ObjCmdProc*)test_install_mutex_counters }, 296 { "read_mutex_counters", (Tcl_ObjCmdProc*)test_read_mutex_counters }, 297 { "clear_mutex_counters", (Tcl_ObjCmdProc*)test_clear_mutex_counters }, 298 }; 299 int i; 300 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 301 Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 302 } 303 memset(&g, 0, sizeof(g)); 304 return SQLITE_OK; 305 } 306 307