Annotation of embedaddon/sqlite3/src/test_mutex.c, revision 1.1.1.1
1.1 misho 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:
15: #include "tcl.h"
16: #include "sqlite3.h"
17: #include "sqliteInt.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 disableTry; /* True to force sqlite3_mutex_try() to fail */
36: int isInit; /* True if initialized */
37: sqlite3_mutex_methods m; /* Interface to "real" mutex system */
38: int aCounter[8]; /* Number of grabs of each type of mutex */
39: sqlite3_mutex aStatic[6]; /* The six static mutexes */
40: } g = {0};
41:
42: /* Return true if the countable mutex is currently held */
43: static int counterMutexHeld(sqlite3_mutex *p){
44: return g.m.xMutexHeld(p->pReal);
45: }
46:
47: /* Return true if the countable mutex is not currently held */
48: static int counterMutexNotheld(sqlite3_mutex *p){
49: return g.m.xMutexNotheld(p->pReal);
50: }
51:
52: /* Initialize the countable mutex interface
53: ** Or, if g.disableInit is non-zero, then do not initialize but instead
54: ** return the value of g.disableInit as the result code. This can be used
55: ** to simulate an initialization failure.
56: */
57: static int counterMutexInit(void){
58: int rc;
59: if( g.disableInit ) return g.disableInit;
60: rc = g.m.xMutexInit();
61: g.isInit = 1;
62: return rc;
63: }
64:
65: /*
66: ** Uninitialize the mutex subsystem
67: */
68: static int counterMutexEnd(void){
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==SQLITE_MUTEX_FAST || eType==SQLITE_MUTEX_RECURSIVE ){
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==SQLITE_MUTEX_FAST || p->eType==SQLITE_MUTEX_RECURSIVE ){
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: if( g.disableTry ) return SQLITE_BUSY;
124: return g.m.xMutexTry(p->pReal);
125: }
126:
127: /* Leave a mutex
128: */
129: static void counterMutexLeave(sqlite3_mutex *p){
130: assert( g.isInit );
131: g.m.xMutexLeave(p->pReal);
132: }
133:
134: /*
135: ** sqlite3_shutdown
136: */
137: static int test_shutdown(
138: void * clientData,
139: Tcl_Interp *interp,
140: int objc,
141: Tcl_Obj *CONST objv[]
142: ){
143: int rc;
144:
145: if( objc!=1 ){
146: Tcl_WrongNumArgs(interp, 1, objv, "");
147: return TCL_ERROR;
148: }
149:
150: rc = sqlite3_shutdown();
151: Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
152: return TCL_OK;
153: }
154:
155: /*
156: ** sqlite3_initialize
157: */
158: static int test_initialize(
159: void * clientData,
160: Tcl_Interp *interp,
161: int objc,
162: Tcl_Obj *CONST objv[]
163: ){
164: int rc;
165:
166: if( objc!=1 ){
167: Tcl_WrongNumArgs(interp, 1, objv, "");
168: return TCL_ERROR;
169: }
170:
171: rc = sqlite3_initialize();
172: Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
173: return TCL_OK;
174: }
175:
176: /*
177: ** install_mutex_counters BOOLEAN
178: */
179: static int test_install_mutex_counters(
180: void * clientData,
181: Tcl_Interp *interp,
182: int objc,
183: Tcl_Obj *CONST objv[]
184: ){
185: int rc = SQLITE_OK;
186: int isInstall;
187:
188: sqlite3_mutex_methods counter_methods = {
189: counterMutexInit,
190: counterMutexEnd,
191: counterMutexAlloc,
192: counterMutexFree,
193: counterMutexEnter,
194: counterMutexTry,
195: counterMutexLeave,
196: counterMutexHeld,
197: counterMutexNotheld
198: };
199:
200: if( objc!=2 ){
201: Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
202: return TCL_ERROR;
203: }
204: if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
205: return TCL_ERROR;
206: }
207:
208: assert(isInstall==0 || isInstall==1);
209: assert(g.isInstalled==0 || g.isInstalled==1);
210: if( isInstall==g.isInstalled ){
211: Tcl_AppendResult(interp, "mutex counters are ", 0);
212: Tcl_AppendResult(interp, isInstall?"already installed":"not installed", 0);
213: return TCL_ERROR;
214: }
215:
216: if( isInstall ){
217: assert( g.m.xMutexAlloc==0 );
218: rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m);
219: if( rc==SQLITE_OK ){
220: sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods);
221: }
222: g.disableTry = 0;
223: }else{
224: assert( g.m.xMutexAlloc );
225: rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m);
226: memset(&g.m, 0, sizeof(sqlite3_mutex_methods));
227: }
228:
229: if( rc==SQLITE_OK ){
230: g.isInstalled = isInstall;
231: }
232:
233: Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
234: return TCL_OK;
235: }
236:
237: /*
238: ** read_mutex_counters
239: */
240: static int test_read_mutex_counters(
241: void * clientData,
242: Tcl_Interp *interp,
243: int objc,
244: Tcl_Obj *CONST objv[]
245: ){
246: Tcl_Obj *pRet;
247: int ii;
248: char *aName[8] = {
249: "fast", "recursive", "static_master", "static_mem",
250: "static_open", "static_prng", "static_lru", "static_pmem"
251: };
252:
253: if( objc!=1 ){
254: Tcl_WrongNumArgs(interp, 1, objv, "");
255: return TCL_ERROR;
256: }
257:
258: pRet = Tcl_NewObj();
259: Tcl_IncrRefCount(pRet);
260: for(ii=0; ii<8; ii++){
261: Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1));
262: Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii]));
263: }
264: Tcl_SetObjResult(interp, pRet);
265: Tcl_DecrRefCount(pRet);
266:
267: return TCL_OK;
268: }
269:
270: /*
271: ** clear_mutex_counters
272: */
273: static int test_clear_mutex_counters(
274: void * clientData,
275: Tcl_Interp *interp,
276: int objc,
277: Tcl_Obj *CONST objv[]
278: ){
279: int ii;
280:
281: if( objc!=1 ){
282: Tcl_WrongNumArgs(interp, 1, objv, "");
283: return TCL_ERROR;
284: }
285:
286: for(ii=0; ii<8; ii++){
287: g.aCounter[ii] = 0;
288: }
289: return TCL_OK;
290: }
291:
292: /*
293: ** Create and free a mutex. Return the mutex pointer. The pointer
294: ** will be invalid since the mutex has already been freed. The
295: ** return pointer just checks to see if the mutex really was allocated.
296: */
297: static int test_alloc_mutex(
298: void * clientData,
299: Tcl_Interp *interp,
300: int objc,
301: Tcl_Obj *CONST objv[]
302: ){
303: #if SQLITE_THREADSAFE
304: sqlite3_mutex *p = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
305: char zBuf[100];
306: sqlite3_mutex_free(p);
307: sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p);
308: Tcl_AppendResult(interp, zBuf, (char*)0);
309: #endif
310: return TCL_OK;
311: }
312:
313: /*
314: ** sqlite3_config OPTION
315: **
316: ** OPTION can be either one of the keywords:
317: **
318: ** SQLITE_CONFIG_SINGLETHREAD
319: ** SQLITE_CONFIG_MULTITHREAD
320: ** SQLITE_CONFIG_SERIALIZED
321: **
322: ** Or OPTION can be an raw integer.
323: */
324: static int test_config(
325: void * clientData,
326: Tcl_Interp *interp,
327: int objc,
328: Tcl_Obj *CONST objv[]
329: ){
330: struct ConfigOption {
331: const char *zName;
332: int iValue;
333: } aOpt[] = {
334: {"singlethread", SQLITE_CONFIG_SINGLETHREAD},
335: {"multithread", SQLITE_CONFIG_MULTITHREAD},
336: {"serialized", SQLITE_CONFIG_SERIALIZED},
337: {0, 0}
338: };
339: int s = sizeof(struct ConfigOption);
340: int i;
341: int rc;
342:
343: if( objc!=2 ){
344: Tcl_WrongNumArgs(interp, 1, objv, "");
345: return TCL_ERROR;
346: }
347:
348: if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){
349: if( Tcl_GetIntFromObj(interp, objv[1], &i) ){
350: return TCL_ERROR;
351: }
352: }else{
353: i = aOpt[i].iValue;
354: }
355:
356: rc = sqlite3_config(i);
357: Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
358: return TCL_OK;
359: }
360:
361: static sqlite3 *getDbPointer(Tcl_Interp *pInterp, Tcl_Obj *pObj){
362: sqlite3 *db;
363: Tcl_CmdInfo info;
364: char *zCmd = Tcl_GetString(pObj);
365: if( Tcl_GetCommandInfo(pInterp, zCmd, &info) ){
366: db = *((sqlite3 **)info.objClientData);
367: }else{
368: db = (sqlite3*)sqlite3TestTextToPtr(zCmd);
369: }
370: assert( db );
371: return db;
372: }
373:
374: static int test_enter_db_mutex(
375: void * clientData,
376: Tcl_Interp *interp,
377: int objc,
378: Tcl_Obj *CONST objv[]
379: ){
380: sqlite3 *db;
381: if( objc!=2 ){
382: Tcl_WrongNumArgs(interp, 1, objv, "DB");
383: return TCL_ERROR;
384: }
385: db = getDbPointer(interp, objv[1]);
386: if( !db ){
387: return TCL_ERROR;
388: }
389: sqlite3_mutex_enter(sqlite3_db_mutex(db));
390: return TCL_OK;
391: }
392:
393: static int test_leave_db_mutex(
394: void * clientData,
395: Tcl_Interp *interp,
396: int objc,
397: Tcl_Obj *CONST objv[]
398: ){
399: sqlite3 *db;
400: if( objc!=2 ){
401: Tcl_WrongNumArgs(interp, 1, objv, "DB");
402: return TCL_ERROR;
403: }
404: db = getDbPointer(interp, objv[1]);
405: if( !db ){
406: return TCL_ERROR;
407: }
408: sqlite3_mutex_leave(sqlite3_db_mutex(db));
409: return TCL_OK;
410: }
411:
412: int Sqlitetest_mutex_Init(Tcl_Interp *interp){
413: static struct {
414: char *zName;
415: Tcl_ObjCmdProc *xProc;
416: } aCmd[] = {
417: { "sqlite3_shutdown", (Tcl_ObjCmdProc*)test_shutdown },
418: { "sqlite3_initialize", (Tcl_ObjCmdProc*)test_initialize },
419: { "sqlite3_config", (Tcl_ObjCmdProc*)test_config },
420:
421: { "enter_db_mutex", (Tcl_ObjCmdProc*)test_enter_db_mutex },
422: { "leave_db_mutex", (Tcl_ObjCmdProc*)test_leave_db_mutex },
423:
424: { "alloc_dealloc_mutex", (Tcl_ObjCmdProc*)test_alloc_mutex },
425: { "install_mutex_counters", (Tcl_ObjCmdProc*)test_install_mutex_counters },
426: { "read_mutex_counters", (Tcl_ObjCmdProc*)test_read_mutex_counters },
427: { "clear_mutex_counters", (Tcl_ObjCmdProc*)test_clear_mutex_counters },
428: };
429: int i;
430: for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
431: Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
432: }
433:
434: Tcl_LinkVar(interp, "disable_mutex_init",
435: (char*)&g.disableInit, TCL_LINK_INT);
436: Tcl_LinkVar(interp, "disable_mutex_try",
437: (char*)&g.disableTry, TCL_LINK_INT);
438: return SQLITE_OK;
439: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>