test_mutex.c 10 KB

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