danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 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 | ** |
danielk1977 | 5f6d026 | 2008-11-04 14:55:47 +0000 | [diff] [blame] | 13 | ** $Id: test_mutex.c,v 1.12 2008/11/04 14:55:47 danielk1977 Exp $ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 14 | */ |
| 15 | |
| 16 | #include "tcl.h" |
| 17 | #include "sqlite3.h" |
danielk1977 | b27475b | 2008-07-19 13:43:23 +0000 | [diff] [blame] | 18 | #include "sqliteInt.h" |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 19 | #include <stdlib.h> |
| 20 | #include <assert.h> |
| 21 | #include <string.h> |
| 22 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 23 | /* defined in test1.c */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 24 | const char *sqlite3TestErrorName(int); |
| 25 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 26 | /* A countable mutex */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 27 | struct sqlite3_mutex { |
| 28 | sqlite3_mutex *pReal; |
| 29 | int eType; |
| 30 | }; |
| 31 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 32 | /* State variables */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 33 | static struct test_mutex_globals { |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 34 | int isInstalled; /* True if installed */ |
| 35 | int disableInit; /* True to cause sqlite3_initalize() to fail */ |
drh | 8a42cbd | 2008-07-10 18:13:42 +0000 | [diff] [blame] | 36 | int disableTry; /* True to force sqlite3_mutex_try() to fail */ |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 37 | int isInit; /* True if initialized */ |
| 38 | sqlite3_mutex_methods m; /* Interface to "real" mutex system */ |
| 39 | int aCounter[8]; /* Number of grabs of each type of mutex */ |
| 40 | sqlite3_mutex aStatic[6]; /* The six static mutexes */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 41 | } g; |
| 42 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 43 | /* Return true if the countable mutex is currently held */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 44 | static int counterMutexHeld(sqlite3_mutex *p){ |
| 45 | return g.m.xMutexHeld(p->pReal); |
| 46 | } |
| 47 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 48 | /* Return true if the countable mutex is not currently held */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 49 | static int counterMutexNotheld(sqlite3_mutex *p){ |
| 50 | return g.m.xMutexNotheld(p->pReal); |
| 51 | } |
| 52 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 53 | /* Initialize the countable mutex interface |
| 54 | ** Or, if g.disableInit is non-zero, then do not initialize but instead |
| 55 | ** return the value of g.disableInit as the result code. This can be used |
| 56 | ** to simulate an initialization failure. |
| 57 | */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 58 | static int counterMutexInit(void){ |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 59 | int rc; |
| 60 | if( g.disableInit ) return g.disableInit; |
| 61 | rc = g.m.xMutexInit(); |
| 62 | g.isInit = 1; |
| 63 | return rc; |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 64 | } |
| 65 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 66 | /* |
| 67 | ** Uninitialize the mutex subsystem |
| 68 | */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 69 | static int counterMutexEnd(void){ |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 70 | g.isInit = 0; |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 71 | return g.m.xMutexEnd(); |
| 72 | } |
| 73 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 74 | /* |
| 75 | ** Allocate a countable mutex |
| 76 | */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 77 | static sqlite3_mutex *counterMutexAlloc(int eType){ |
| 78 | sqlite3_mutex *pReal; |
| 79 | sqlite3_mutex *pRet = 0; |
| 80 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 81 | assert( g.isInit ); |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 82 | assert(eType<8 && eType>=0); |
| 83 | |
| 84 | pReal = g.m.xMutexAlloc(eType); |
| 85 | if( !pReal ) return 0; |
| 86 | |
drh | c8d7567 | 2008-07-08 02:12:37 +0000 | [diff] [blame] | 87 | if( eType==SQLITE_MUTEX_FAST || eType==SQLITE_MUTEX_RECURSIVE ){ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 88 | pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex)); |
| 89 | }else{ |
| 90 | pRet = &g.aStatic[eType-2]; |
| 91 | } |
| 92 | |
| 93 | pRet->eType = eType; |
| 94 | pRet->pReal = pReal; |
| 95 | return pRet; |
| 96 | } |
| 97 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 98 | /* |
| 99 | ** Free a countable mutex |
| 100 | */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 101 | static void counterMutexFree(sqlite3_mutex *p){ |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 102 | assert( g.isInit ); |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 103 | g.m.xMutexFree(p->pReal); |
drh | c8d7567 | 2008-07-08 02:12:37 +0000 | [diff] [blame] | 104 | if( p->eType==SQLITE_MUTEX_FAST || p->eType==SQLITE_MUTEX_RECURSIVE ){ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 105 | free(p); |
| 106 | } |
| 107 | } |
| 108 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 109 | /* |
| 110 | ** Enter a countable mutex. Block until entry is safe. |
| 111 | */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 112 | static void counterMutexEnter(sqlite3_mutex *p){ |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 113 | assert( g.isInit ); |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 114 | g.aCounter[p->eType]++; |
| 115 | g.m.xMutexEnter(p->pReal); |
| 116 | } |
| 117 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 118 | /* |
| 119 | ** Try to enter a mutex. Return true on success. |
| 120 | */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 121 | static int counterMutexTry(sqlite3_mutex *p){ |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 122 | assert( g.isInit ); |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 123 | g.aCounter[p->eType]++; |
drh | 19dd29f | 2008-07-10 20:41:49 +0000 | [diff] [blame] | 124 | if( g.disableTry ) return SQLITE_BUSY; |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 125 | return g.m.xMutexTry(p->pReal); |
| 126 | } |
| 127 | |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 128 | /* Leave a mutex |
| 129 | */ |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 130 | static void counterMutexLeave(sqlite3_mutex *p){ |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 131 | assert( g.isInit ); |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 132 | g.m.xMutexLeave(p->pReal); |
| 133 | } |
| 134 | |
| 135 | /* |
| 136 | ** sqlite3_shutdown |
| 137 | */ |
| 138 | static int test_shutdown( |
| 139 | void * clientData, |
| 140 | Tcl_Interp *interp, |
| 141 | int objc, |
| 142 | Tcl_Obj *CONST objv[] |
| 143 | ){ |
| 144 | int rc; |
| 145 | |
| 146 | if( objc!=1 ){ |
| 147 | Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 148 | return TCL_ERROR; |
| 149 | } |
| 150 | |
| 151 | rc = sqlite3_shutdown(); |
| 152 | Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); |
| 153 | return TCL_OK; |
| 154 | } |
| 155 | |
| 156 | /* |
| 157 | ** sqlite3_initialize |
| 158 | */ |
| 159 | static int test_initialize( |
| 160 | void * clientData, |
| 161 | Tcl_Interp *interp, |
| 162 | int objc, |
| 163 | Tcl_Obj *CONST objv[] |
| 164 | ){ |
| 165 | int rc; |
| 166 | |
| 167 | if( objc!=1 ){ |
| 168 | Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 169 | return TCL_ERROR; |
| 170 | } |
| 171 | |
| 172 | rc = sqlite3_initialize(); |
| 173 | Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); |
| 174 | return TCL_OK; |
| 175 | } |
| 176 | |
| 177 | /* |
| 178 | ** install_mutex_counters BOOLEAN |
| 179 | */ |
| 180 | static int test_install_mutex_counters( |
| 181 | void * clientData, |
| 182 | Tcl_Interp *interp, |
| 183 | int objc, |
| 184 | Tcl_Obj *CONST objv[] |
| 185 | ){ |
| 186 | int rc = SQLITE_OK; |
| 187 | int isInstall; |
| 188 | |
| 189 | sqlite3_mutex_methods counter_methods = { |
| 190 | counterMutexInit, |
danielk1977 | 4a9d1f6 | 2008-06-19 08:51:23 +0000 | [diff] [blame] | 191 | counterMutexEnd, |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 192 | counterMutexAlloc, |
| 193 | counterMutexFree, |
| 194 | counterMutexEnter, |
| 195 | counterMutexTry, |
| 196 | counterMutexLeave, |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 197 | counterMutexHeld, |
| 198 | counterMutexNotheld |
| 199 | }; |
| 200 | |
| 201 | if( objc!=2 ){ |
| 202 | Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); |
| 203 | return TCL_ERROR; |
| 204 | } |
| 205 | if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ |
| 206 | return TCL_ERROR; |
| 207 | } |
| 208 | |
| 209 | assert(isInstall==0 || isInstall==1); |
| 210 | assert(g.isInstalled==0 || g.isInstalled==1); |
| 211 | if( isInstall==g.isInstalled ){ |
| 212 | Tcl_AppendResult(interp, "mutex counters are ", 0); |
| 213 | Tcl_AppendResult(interp, isInstall?"already installed":"not installed", 0); |
| 214 | return TCL_ERROR; |
| 215 | } |
| 216 | |
| 217 | if( isInstall ){ |
| 218 | assert( g.m.xMutexAlloc==0 ); |
| 219 | rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m); |
| 220 | if( rc==SQLITE_OK ){ |
| 221 | sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods); |
| 222 | } |
drh | 8a42cbd | 2008-07-10 18:13:42 +0000 | [diff] [blame] | 223 | g.disableTry = 0; |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 224 | }else{ |
| 225 | assert( g.m.xMutexAlloc ); |
| 226 | rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m); |
| 227 | memset(&g.m, 0, sizeof(sqlite3_mutex_methods)); |
| 228 | } |
| 229 | |
| 230 | if( rc==SQLITE_OK ){ |
| 231 | g.isInstalled = isInstall; |
| 232 | } |
| 233 | |
| 234 | Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); |
| 235 | return TCL_OK; |
| 236 | } |
| 237 | |
| 238 | /* |
| 239 | ** read_mutex_counters |
| 240 | */ |
| 241 | static int test_read_mutex_counters( |
| 242 | void * clientData, |
| 243 | Tcl_Interp *interp, |
| 244 | int objc, |
| 245 | Tcl_Obj *CONST objv[] |
| 246 | ){ |
| 247 | Tcl_Obj *pRet; |
| 248 | int ii; |
| 249 | char *aName[8] = { |
| 250 | "fast", "recursive", "static_master", "static_mem", |
| 251 | "static_mem2", "static_prng", "static_lru", "static_lru2" |
| 252 | }; |
| 253 | |
| 254 | if( objc!=1 ){ |
| 255 | Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 256 | return TCL_ERROR; |
| 257 | } |
| 258 | |
| 259 | pRet = Tcl_NewObj(); |
| 260 | Tcl_IncrRefCount(pRet); |
| 261 | for(ii=0; ii<8; ii++){ |
| 262 | Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1)); |
| 263 | Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii])); |
| 264 | } |
| 265 | Tcl_SetObjResult(interp, pRet); |
| 266 | Tcl_DecrRefCount(pRet); |
| 267 | |
| 268 | return TCL_OK; |
| 269 | } |
| 270 | |
| 271 | /* |
| 272 | ** clear_mutex_counters |
| 273 | */ |
| 274 | static int test_clear_mutex_counters( |
| 275 | void * clientData, |
| 276 | Tcl_Interp *interp, |
| 277 | int objc, |
| 278 | Tcl_Obj *CONST objv[] |
| 279 | ){ |
| 280 | int ii; |
| 281 | |
| 282 | if( objc!=1 ){ |
| 283 | Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 284 | return TCL_ERROR; |
| 285 | } |
| 286 | |
| 287 | for(ii=0; ii<8; ii++){ |
| 288 | g.aCounter[ii] = 0; |
| 289 | } |
| 290 | return TCL_OK; |
| 291 | } |
| 292 | |
danielk1977 | 59f8c08 | 2008-06-18 17:09:10 +0000 | [diff] [blame] | 293 | /* |
drh | c8d7567 | 2008-07-08 02:12:37 +0000 | [diff] [blame] | 294 | ** Create and free a mutex. Return the mutex pointer. The pointer |
| 295 | ** will be invalid since the mutex has already been freed. The |
| 296 | ** return pointer just checks to see if the mutex really was allocated. |
| 297 | */ |
| 298 | static int test_alloc_mutex( |
| 299 | void * clientData, |
| 300 | Tcl_Interp *interp, |
| 301 | int objc, |
| 302 | Tcl_Obj *CONST objv[] |
| 303 | ){ |
drh | b912f3e | 2008-07-17 17:34:19 +0000 | [diff] [blame] | 304 | #if SQLITE_THREADSAFE |
drh | c8d7567 | 2008-07-08 02:12:37 +0000 | [diff] [blame] | 305 | sqlite3_mutex *p = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); |
| 306 | char zBuf[100]; |
| 307 | sqlite3_mutex_free(p); |
| 308 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p); |
| 309 | Tcl_AppendResult(interp, zBuf, (char*)0); |
drh | b912f3e | 2008-07-17 17:34:19 +0000 | [diff] [blame] | 310 | #endif |
drh | c8d7567 | 2008-07-08 02:12:37 +0000 | [diff] [blame] | 311 | return TCL_OK; |
| 312 | } |
| 313 | |
| 314 | /* |
danielk1977 | 59f8c08 | 2008-06-18 17:09:10 +0000 | [diff] [blame] | 315 | ** sqlite3_config OPTION |
drh | 8a42cbd | 2008-07-10 18:13:42 +0000 | [diff] [blame] | 316 | ** |
| 317 | ** OPTION can be either one of the keywords: |
| 318 | ** |
| 319 | ** SQLITE_CONFIG_SINGLETHREAD |
| 320 | ** SQLITE_CONFIG_MULTITHREAD |
| 321 | ** SQLITE_CONFIG_SERIALIZED |
| 322 | ** |
| 323 | ** Or OPTION can be an raw integer. |
danielk1977 | 59f8c08 | 2008-06-18 17:09:10 +0000 | [diff] [blame] | 324 | */ |
| 325 | static int test_config( |
| 326 | void * clientData, |
| 327 | Tcl_Interp *interp, |
| 328 | int objc, |
| 329 | Tcl_Obj *CONST objv[] |
| 330 | ){ |
| 331 | struct ConfigOption { |
| 332 | const char *zName; |
| 333 | int iValue; |
| 334 | } aOpt[] = { |
| 335 | {"singlethread", SQLITE_CONFIG_SINGLETHREAD}, |
| 336 | {"multithread", SQLITE_CONFIG_MULTITHREAD}, |
| 337 | {"serialized", SQLITE_CONFIG_SERIALIZED}, |
| 338 | {0, 0} |
| 339 | }; |
| 340 | int s = sizeof(struct ConfigOption); |
| 341 | int i; |
| 342 | int rc; |
| 343 | |
| 344 | if( objc!=2 ){ |
| 345 | Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 346 | return TCL_ERROR; |
| 347 | } |
| 348 | |
| 349 | if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){ |
drh | 8a42cbd | 2008-07-10 18:13:42 +0000 | [diff] [blame] | 350 | if( Tcl_GetIntFromObj(interp, objv[1], &i) ){ |
| 351 | return TCL_ERROR; |
| 352 | } |
| 353 | }else{ |
| 354 | i = aOpt[i].iValue; |
danielk1977 | 59f8c08 | 2008-06-18 17:09:10 +0000 | [diff] [blame] | 355 | } |
| 356 | |
drh | 8a42cbd | 2008-07-10 18:13:42 +0000 | [diff] [blame] | 357 | rc = sqlite3_config(i); |
danielk1977 | 59f8c08 | 2008-06-18 17:09:10 +0000 | [diff] [blame] | 358 | Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); |
| 359 | return TCL_OK; |
| 360 | } |
| 361 | |
danielk1977 | 5f6d026 | 2008-11-04 14:55:47 +0000 | [diff] [blame] | 362 | static sqlite3 *getDbPointer(Tcl_Interp *pInterp, Tcl_Obj *pObj){ |
| 363 | sqlite3 *db; |
| 364 | Tcl_CmdInfo info; |
| 365 | char *zCmd = Tcl_GetString(pObj); |
| 366 | if( 1!=Tcl_GetCommandInfo(pInterp, zCmd, &info) ){ |
| 367 | Tcl_AppendResult(pInterp, "No such db-handle: \"", zCmd, "\"", 0); |
| 368 | return 0; |
| 369 | } |
| 370 | db = *((sqlite3 **)info.objClientData); |
| 371 | assert( db ); |
| 372 | return db; |
| 373 | } |
| 374 | |
| 375 | static int test_enter_db_mutex( |
| 376 | void * clientData, |
| 377 | Tcl_Interp *interp, |
| 378 | int objc, |
| 379 | Tcl_Obj *CONST objv[] |
| 380 | ){ |
| 381 | sqlite3 *db; |
| 382 | if( objc!=2 ){ |
| 383 | Tcl_WrongNumArgs(interp, 1, objv, "DB"); |
| 384 | return TCL_ERROR; |
| 385 | } |
| 386 | db = getDbPointer(interp, objv[1]); |
| 387 | if( !db ){ |
| 388 | return TCL_ERROR; |
| 389 | } |
| 390 | sqlite3_mutex_enter(sqlite3_db_mutex(db)); |
| 391 | return TCL_OK; |
| 392 | } |
| 393 | |
| 394 | static int test_leave_db_mutex( |
| 395 | void * clientData, |
| 396 | Tcl_Interp *interp, |
| 397 | int objc, |
| 398 | Tcl_Obj *CONST objv[] |
| 399 | ){ |
| 400 | sqlite3 *db; |
| 401 | if( objc!=2 ){ |
| 402 | Tcl_WrongNumArgs(interp, 1, objv, "DB"); |
| 403 | return TCL_ERROR; |
| 404 | } |
| 405 | db = getDbPointer(interp, objv[1]); |
| 406 | if( !db ){ |
| 407 | return TCL_ERROR; |
| 408 | } |
| 409 | sqlite3_mutex_leave(sqlite3_db_mutex(db)); |
| 410 | return TCL_OK; |
| 411 | } |
| 412 | |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 413 | int Sqlitetest_mutex_Init(Tcl_Interp *interp){ |
| 414 | static struct { |
| 415 | char *zName; |
| 416 | Tcl_ObjCmdProc *xProc; |
| 417 | } aCmd[] = { |
| 418 | { "sqlite3_shutdown", (Tcl_ObjCmdProc*)test_shutdown }, |
| 419 | { "sqlite3_initialize", (Tcl_ObjCmdProc*)test_initialize }, |
danielk1977 | 59f8c08 | 2008-06-18 17:09:10 +0000 | [diff] [blame] | 420 | { "sqlite3_config", (Tcl_ObjCmdProc*)test_config }, |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 421 | |
danielk1977 | 5f6d026 | 2008-11-04 14:55:47 +0000 | [diff] [blame] | 422 | { "enter_db_mutex", (Tcl_ObjCmdProc*)test_enter_db_mutex }, |
| 423 | { "leave_db_mutex", (Tcl_ObjCmdProc*)test_leave_db_mutex }, |
| 424 | |
drh | c8d7567 | 2008-07-08 02:12:37 +0000 | [diff] [blame] | 425 | { "alloc_dealloc_mutex", (Tcl_ObjCmdProc*)test_alloc_mutex }, |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 426 | { "install_mutex_counters", (Tcl_ObjCmdProc*)test_install_mutex_counters }, |
| 427 | { "read_mutex_counters", (Tcl_ObjCmdProc*)test_read_mutex_counters }, |
| 428 | { "clear_mutex_counters", (Tcl_ObjCmdProc*)test_clear_mutex_counters }, |
| 429 | }; |
| 430 | int i; |
| 431 | for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ |
| 432 | Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); |
| 433 | } |
| 434 | memset(&g, 0, sizeof(g)); |
drh | fb45d8c | 2008-07-08 00:06:49 +0000 | [diff] [blame] | 435 | |
| 436 | Tcl_LinkVar(interp, "disable_mutex_init", |
| 437 | (char*)&g.disableInit, TCL_LINK_INT); |
drh | 8a42cbd | 2008-07-10 18:13:42 +0000 | [diff] [blame] | 438 | Tcl_LinkVar(interp, "disable_mutex_try", |
| 439 | (char*)&g.disableTry, TCL_LINK_INT); |
danielk1977 | 1a9ed0b | 2008-06-18 09:45:56 +0000 | [diff] [blame] | 440 | return SQLITE_OK; |
| 441 | } |