wasCSharpSQLite – Blame information for rev
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | using System.Diagnostics; |
2 | |||
3 | namespace Community.CsharpSqlite |
||
4 | { |
||
5 | #if TCLSH |
||
6 | using tcl.lang; |
||
7 | using Tcl_Interp = tcl.lang.Interp; |
||
8 | using Tcl_Obj = tcl.lang.TclObject; |
||
9 | using System.Text; |
||
10 | |||
11 | |||
12 | public partial class Sqlite3 |
||
13 | { |
||
14 | /* |
||
15 | ** 2008 June 18 |
||
16 | ** |
||
17 | ** The author disclaims copyright to this source code. In place of |
||
18 | ** a legal notice, here is a blessing: |
||
19 | ** |
||
20 | ** May you do good and not evil. |
||
21 | ** May you find forgiveness for yourself and forgive others. |
||
22 | ** May you share freely, never taking more than you give. |
||
23 | ** |
||
24 | ************************************************************************* |
||
25 | ** This file contains test logic for the sqlite3_mutex interfaces. |
||
26 | ************************************************************************* |
||
27 | ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart |
||
28 | ** C#-SQLite is an independent reimplementation of the SQLite software library |
||
29 | ** |
||
30 | ** SQLITE_SOURCE_ID: 2011-01-28 17:03:50 ed759d5a9edb3bba5f48f243df47be29e3fe8cd7 |
||
31 | ** |
||
32 | ************************************************************************* |
||
33 | */ |
||
34 | |||
35 | //#include "tcl.h" |
||
36 | //#include "sqlite3.h" |
||
37 | //#include "sqliteInt.h" |
||
38 | //#include <stdlib.h> |
||
39 | //#include <assert.h> |
||
40 | //#include <string.h> |
||
41 | |||
42 | /* defined in test1.c */ |
||
43 | //string sqlite3TestErrorName(int); |
||
44 | |||
45 | /* A countable mutex */ |
||
46 | public partial class sqlite3_mutex |
||
47 | { |
||
48 | public sqlite3_mutex pReal; |
||
49 | public int eType; |
||
50 | }; |
||
51 | |||
52 | static Var.SQLITE3_GETSET disableInit = new Var.SQLITE3_GETSET( "disable_mutex_init" ); |
||
53 | static Var.SQLITE3_GETSET disableTry = new Var.SQLITE3_GETSET( "disable_mutex_try" ); |
||
54 | |||
55 | /* State variables */ |
||
56 | public class test_mutex_globals |
||
57 | { |
||
58 | public bool isInstalled; /* True if installed */ |
||
59 | public bool disableInit; /* True to cause sqlite3_initalize() to fail */ |
||
60 | public bool disableTry; /* True to force sqlite3_mutex_try() to fail */ |
||
61 | public bool isInit; /* True if initialized */ |
||
62 | public sqlite3_mutex_methods m = new sqlite3_mutex_methods(); /* Interface to "real" mutex system */ |
||
63 | public int[] aCounter = new int[8]; /* Number of grabs of each type of mutex */ |
||
64 | public sqlite3_mutex[] aStatic = new sqlite3_mutex[6]; /* The six static mutexes */ |
||
65 | |||
66 | public test_mutex_globals() |
||
67 | { |
||
68 | for ( int i = 0; i < aStatic.Length; i++ ) |
||
69 | aStatic[i] = new sqlite3_mutex(); |
||
70 | } |
||
71 | } |
||
72 | |||
73 | static test_mutex_globals g = new test_mutex_globals(); |
||
74 | |||
75 | /* Return true if the countable mutex is currently held */ |
||
76 | static bool counterMutexHeld( sqlite3_mutex p ) |
||
77 | { |
||
78 | return g.m.xMutexHeld( p.pReal ); |
||
79 | } |
||
80 | |||
81 | /* Return true if the countable mutex is not currently held */ |
||
82 | static bool counterMutexNotheld( sqlite3_mutex p ) |
||
83 | { |
||
84 | return g.m.xMutexNotheld( p.pReal ); |
||
85 | } |
||
86 | |||
87 | /* Initialize the countable mutex interface |
||
88 | ** Or, if g.disableInit is non-zero, then do not initialize but instead |
||
89 | ** return the value of g.disableInit as the result code. This can be used |
||
90 | ** to simulate an initialization failure. |
||
91 | */ |
||
92 | static int counterMutexInit() |
||
93 | { |
||
94 | int rc; |
||
95 | if ( g.disableInit ) |
||
96 | return g.disableInit ? 1 : 0; |
||
97 | rc = g.m.xMutexInit(); |
||
98 | g.isInit = true; |
||
99 | return rc; |
||
100 | } |
||
101 | |||
102 | /* |
||
103 | ** Uninitialize the mutex subsystem |
||
104 | */ |
||
105 | static int counterMutexEnd() |
||
106 | { |
||
107 | g.isInit = false; |
||
108 | return g.m.xMutexEnd(); |
||
109 | } |
||
110 | |||
111 | /* |
||
112 | ** Allocate a countable mutex |
||
113 | */ |
||
114 | static sqlite3_mutex counterMutexAlloc( int eType ) |
||
115 | { |
||
116 | sqlite3_mutex pReal; |
||
117 | sqlite3_mutex pRet = null; |
||
118 | |||
119 | Debug.Assert( g.isInit ); |
||
120 | Debug.Assert( eType < 8 && eType >= 0 ); |
||
121 | |||
122 | pReal = g.m.xMutexAlloc( eType ); |
||
123 | if ( null == pReal ) |
||
124 | return null; |
||
125 | |||
126 | if ( eType == SQLITE_MUTEX_FAST || eType == SQLITE_MUTEX_RECURSIVE ) |
||
127 | { |
||
128 | pRet = new sqlite3_mutex(); |
||
129 | ;//(sqlite3_mutex)malloc( sizeof( sqlite3_mutex ) ); |
||
130 | } |
||
131 | else |
||
132 | { |
||
133 | pRet = g.aStatic[eType - 2]; |
||
134 | } |
||
135 | |||
136 | pRet.eType = eType; |
||
137 | pRet.pReal = pReal; |
||
138 | return pRet; |
||
139 | } |
||
140 | |||
141 | /* |
||
142 | ** Free a countable mutex |
||
143 | */ |
||
144 | static void counterMutexFree( sqlite3_mutex p ) |
||
145 | { |
||
146 | Debug.Assert( g.isInit ); |
||
147 | g.m.xMutexFree( p.pReal ); |
||
148 | if ( p.eType == SQLITE_MUTEX_FAST || p.eType == SQLITE_MUTEX_RECURSIVE ) |
||
149 | { |
||
150 | p = null;//free(p); |
||
151 | } |
||
152 | } |
||
153 | |||
154 | /* |
||
155 | ** Enter a countable mutex. Block until entry is safe. |
||
156 | */ |
||
157 | static void counterMutexEnter( sqlite3_mutex p ) |
||
158 | { |
||
159 | Debug.Assert( g.isInit ); |
||
160 | g.aCounter[p.eType]++; |
||
161 | g.m.xMutexEnter( p.pReal ); |
||
162 | } |
||
163 | |||
164 | /* |
||
165 | ** Try to enter a mutex. Return true on success. |
||
166 | */ |
||
167 | static int counterMutexTry( sqlite3_mutex p ) |
||
168 | { |
||
169 | Debug.Assert( g.isInit ); |
||
170 | g.aCounter[p.eType]++; |
||
171 | if ( g.disableTry ) |
||
172 | return SQLITE_BUSY; |
||
173 | return g.m.xMutexTry( p.pReal ); |
||
174 | } |
||
175 | |||
176 | /* Leave a mutex |
||
177 | */ |
||
178 | static void counterMutexLeave( sqlite3_mutex p ) |
||
179 | { |
||
180 | Debug.Assert( g.isInit ); |
||
181 | g.m.xMutexLeave( p.pReal ); |
||
182 | } |
||
183 | |||
184 | /* |
||
185 | ** sqlite3_shutdown |
||
186 | */ |
||
187 | static int test_shutdown( |
||
188 | object clientdata, |
||
189 | Tcl_Interp interp, |
||
190 | int objc, |
||
191 | Tcl_Obj[] objv |
||
192 | ) |
||
193 | { |
||
194 | int rc; |
||
195 | |||
196 | if ( objc != 1 ) |
||
197 | { |
||
198 | TCL.Tcl_WrongNumArgs( interp, 1, objv, "" ); |
||
199 | return TCL.TCL_ERROR; |
||
200 | } |
||
201 | |||
202 | rc = sqlite3_shutdown(); |
||
203 | TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_VOLATILE ); |
||
204 | return TCL.TCL_OK; |
||
205 | } |
||
206 | |||
207 | /* |
||
208 | ** sqlite3_initialize |
||
209 | */ |
||
210 | static int test_initialize( |
||
211 | object clientdata, |
||
212 | Tcl_Interp interp, |
||
213 | int objc, |
||
214 | Tcl_Obj[] objv ) |
||
215 | { |
||
216 | int rc; |
||
217 | |||
218 | if ( objc != 1 ) |
||
219 | { |
||
220 | TCL.Tcl_WrongNumArgs( interp, 1, objv, "" ); |
||
221 | return TCL.TCL_ERROR; |
||
222 | } |
||
223 | |||
224 | rc = sqlite3_initialize(); |
||
225 | TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_VOLATILE ); |
||
226 | return TCL.TCL_OK; |
||
227 | } |
||
228 | |||
229 | /* |
||
230 | ** install_mutex_counters BOOLEAN |
||
231 | */ |
||
232 | static int test_install_mutex_counters( |
||
233 | object clientdata, |
||
234 | Tcl_Interp interp, |
||
235 | int objc, |
||
236 | Tcl_Obj[] objv |
||
237 | ) |
||
238 | { |
||
239 | int rc = SQLITE_OK; |
||
240 | bool isInstall = false; |
||
241 | |||
242 | sqlite3_mutex_methods counter_methods = new sqlite3_mutex_methods( |
||
243 | (dxMutexInit)counterMutexInit, |
||
244 | (dxMutexEnd)counterMutexEnd, |
||
245 | (dxMutexAlloc)counterMutexAlloc, |
||
246 | (dxMutexFree)counterMutexFree, |
||
247 | (dxMutexEnter)counterMutexEnter, |
||
248 | (dxMutexTry)counterMutexTry, |
||
249 | (dxMutexLeave)counterMutexLeave, |
||
250 | (dxMutexHeld)counterMutexHeld, |
||
251 | (dxMutexNotheld)counterMutexNotheld |
||
252 | ); |
||
253 | |||
254 | if ( objc != 2 ) |
||
255 | { |
||
256 | TCL.Tcl_WrongNumArgs( interp, 1, objv, "BOOLEAN" ); |
||
257 | return TCL.TCL_ERROR; |
||
258 | } |
||
259 | if ( TCL.Tcl_GetBoolean( interp, objv[1], out isInstall )) |
||
260 | { |
||
261 | return TCL.TCL_ERROR; |
||
262 | } |
||
263 | |||
264 | Debug.Assert( isInstall == false || isInstall == true ); |
||
265 | Debug.Assert( g.isInstalled == false || g.isInstalled == true ); |
||
266 | if ( isInstall == g.isInstalled ) |
||
267 | { |
||
268 | TCL.Tcl_AppendResult( interp, "mutex counters are " ); |
||
269 | TCL.Tcl_AppendResult( interp, isInstall ? "already installed" : "not installed" ); |
||
270 | return TCL.TCL_ERROR; |
||
271 | } |
||
272 | |||
273 | if ( isInstall ) |
||
274 | { |
||
275 | Debug.Assert( g.m.xMutexAlloc == null ); |
||
276 | rc = sqlite3_config( SQLITE_CONFIG_GETMUTEX, ref g.m ); |
||
277 | if ( rc == SQLITE_OK ) |
||
278 | { |
||
279 | sqlite3_config( SQLITE_CONFIG_MUTEX, counter_methods ); |
||
280 | } |
||
281 | g.disableTry = false; |
||
282 | } |
||
283 | else |
||
284 | { |
||
285 | Debug.Assert( g.m.xMutexAlloc != null ); |
||
286 | rc = sqlite3_config( SQLITE_CONFIG_MUTEX, g.m ); |
||
287 | g.m = new sqlite3_mutex_methods();// memset( &g.m, 0, sizeof( sqlite3_mutex_methods ) ); |
||
288 | } |
||
289 | |||
290 | if ( rc == SQLITE_OK ) |
||
291 | { |
||
292 | g.isInstalled = isInstall; |
||
293 | } |
||
294 | |||
295 | TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_VOLATILE ); |
||
296 | return TCL.TCL_OK; |
||
297 | } |
||
298 | |||
299 | /* |
||
300 | ** read_mutex_counters |
||
301 | */ |
||
302 | static int test_read_mutex_counters( |
||
303 | object clientdata, |
||
304 | Tcl_Interp interp, |
||
305 | int objc, |
||
306 | Tcl_Obj[] objv |
||
307 | ) |
||
308 | { |
||
309 | Tcl_Obj pRet; |
||
310 | int ii; |
||
311 | string[] aName = new string[] { |
||
312 | "fast", "recursive", "static_master", "static_mem", |
||
313 | "static_open", "static_prng", "static_lru", "static_pmem" |
||
314 | }; |
||
315 | |||
316 | if ( objc != 1 ) |
||
317 | { |
||
318 | TCL.Tcl_WrongNumArgs( interp, 1, objv, "" ); |
||
319 | return TCL.TCL_ERROR; |
||
320 | } |
||
321 | |||
322 | pRet = TCL.Tcl_NewObj(); |
||
323 | TCL.Tcl_IncrRefCount( pRet ); |
||
324 | for ( ii = 0; ii < 8; ii++ ) |
||
325 | { |
||
326 | TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewStringObj( aName[ii], -1 ) ); |
||
327 | TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewIntObj( g.aCounter[ii] ) ); |
||
328 | } |
||
329 | TCL.Tcl_SetObjResult( interp, pRet ); |
||
330 | TCL.Tcl_DecrRefCount( ref pRet ); |
||
331 | |||
332 | return TCL.TCL_OK; |
||
333 | } |
||
334 | |||
335 | /* |
||
336 | ** clear_mutex_counters |
||
337 | */ |
||
338 | static int test_clear_mutex_counters( |
||
339 | object clientdata, |
||
340 | Tcl_Interp interp, |
||
341 | int objc, |
||
342 | Tcl_Obj[] objv |
||
343 | ) |
||
344 | { |
||
345 | int ii; |
||
346 | |||
347 | if ( objc != 1 ) |
||
348 | { |
||
349 | TCL.Tcl_WrongNumArgs( interp, 1, objv, "" ); |
||
350 | return TCL.TCL_ERROR; |
||
351 | } |
||
352 | |||
353 | for ( ii = 0; ii < 8; ii++ ) |
||
354 | { |
||
355 | g.aCounter[ii] = 0; |
||
356 | } |
||
357 | return TCL.TCL_OK; |
||
358 | } |
||
359 | |||
360 | /* |
||
361 | ** Create and free a mutex. Return the mutex pointer. The pointer |
||
362 | ** will be invalid since the mutex has already been freed. The |
||
363 | ** return pointer just checks to see if the mutex really was allocated. |
||
364 | */ |
||
365 | static int test_alloc_mutex( |
||
366 | object clientdata, |
||
367 | Tcl_Interp interp, |
||
368 | int objc, |
||
369 | Tcl_Obj[] objv ) |
||
370 | { |
||
371 | #if SQLITE_THREADSAFE |
||
372 | sqlite3_mutex p = sqlite3_mutex_alloc( SQLITE_MUTEX_FAST ); |
||
373 | StringBuilder zBuf = new StringBuilder( 100 ); |
||
374 | sqlite3_mutex_free( p ); |
||
375 | sqlite3_snprintf( 100, zBuf, "->%p", p ); |
||
376 | TCL.Tcl_AppendResult( interp, zBuf ); |
||
377 | #endif |
||
378 | return TCL.TCL_OK; |
||
379 | } |
||
380 | |||
381 | /* |
||
382 | ** sqlite3_config OPTION |
||
383 | ** |
||
384 | ** OPTION can be either one of the keywords: |
||
385 | ** |
||
386 | ** SQLITE_CONFIG_SINGLETHREAD |
||
387 | ** SQLITE_CONFIG_MULTITHREAD |
||
388 | ** SQLITE_CONFIG_SERIALIZED |
||
389 | ** |
||
390 | ** Or OPTION can be an raw integer. |
||
391 | */ |
||
392 | struct ConfigOption |
||
393 | { |
||
394 | public string zName; |
||
395 | public int iValue; |
||
396 | public ConfigOption( string zName, int iValue ) |
||
397 | { |
||
398 | this.zName = zName; |
||
399 | this.iValue = iValue; |
||
400 | } |
||
401 | } |
||
402 | static bool Tcl_GetIndexFromObjStruct( Interp interp, TclObject to, ConfigOption[] table, int s, string msg, int flags, out int index ) |
||
403 | { |
||
404 | try |
||
405 | { |
||
406 | for ( index = 0; index < table.Length; index++ ) |
||
407 | { |
||
408 | if ( table[index].zName == msg ) |
||
409 | return false; |
||
410 | } |
||
411 | return true; |
||
412 | } |
||
413 | catch |
||
414 | { |
||
415 | index = 0; |
||
416 | return true; |
||
417 | } |
||
418 | } |
||
419 | |||
420 | |||
421 | static int test_config( |
||
422 | object clientdata, |
||
423 | Tcl_Interp interp, |
||
424 | int objc, |
||
425 | Tcl_Obj[] objv |
||
426 | ) |
||
427 | { |
||
428 | ConfigOption[] aOpt = new ConfigOption[] { |
||
429 | new ConfigOption("singlethread", SQLITE_CONFIG_SINGLETHREAD), |
||
430 | new ConfigOption("multithread", SQLITE_CONFIG_MULTITHREAD), |
||
431 | new ConfigOption("serialized", SQLITE_CONFIG_SERIALIZED), |
||
432 | new ConfigOption(null,0) |
||
433 | }; |
||
434 | int s = aOpt.Length;//sizeof(struct ConfigOption); |
||
435 | int i = 0; |
||
436 | int rc; |
||
437 | |||
438 | if ( objc != 2 ) |
||
439 | { |
||
440 | TCL.Tcl_WrongNumArgs( interp, 1, objv, "" ); |
||
441 | return TCL.TCL_ERROR; |
||
442 | } |
||
443 | |||
444 | if ( Tcl_GetIndexFromObjStruct( interp, objv[1], aOpt, s, "flag", 0, out i ) ) |
||
445 | { |
||
446 | if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out i ) ) |
||
447 | { |
||
448 | return TCL.TCL_ERROR; |
||
449 | } |
||
450 | } |
||
451 | else |
||
452 | { |
||
453 | i = aOpt[i].iValue; |
||
454 | } |
||
455 | |||
456 | rc = sqlite3_config( i ); |
||
457 | TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_VOLATILE ); |
||
458 | return TCL.TCL_OK; |
||
459 | } |
||
460 | |||
461 | //static sqlite3 *getDbPointer(Tcl_Interp *pInterp, TCL.TCL_Obj *pObj){ |
||
462 | //sqlite3 db; |
||
463 | //Tcl_CmdInfo info; |
||
464 | //string zCmd = TCL.Tcl_GetString(pObj); |
||
465 | //if( TCL.Tcl_GetCommandInfo(pInterp, zCmd, &info) ){ |
||
466 | // db = *((sqlite3 *)info.objClientData); |
||
467 | //}else{ |
||
468 | // db = (sqlite3)sqlite3TestTextToPtr(zCmd); |
||
469 | //} |
||
470 | //Debug.Assert( db ); |
||
471 | //return db; |
||
472 | |||
473 | static int test_enter_db_mutex( |
||
474 | object clientdata, |
||
475 | Tcl_Interp interp, |
||
476 | int objc, |
||
477 | Tcl_Obj[] objv |
||
478 | ) |
||
479 | { |
||
480 | sqlite3 db = null; |
||
481 | if ( objc != 2 ) |
||
482 | { |
||
483 | TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB" ); |
||
484 | return TCL.TCL_ERROR; |
||
485 | } |
||
486 | getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ); |
||
487 | if ( null == db ) |
||
488 | { |
||
489 | return TCL.TCL_ERROR; |
||
490 | } |
||
491 | sqlite3_mutex_enter( sqlite3_db_mutex( db ) ); |
||
492 | return TCL.TCL_OK; |
||
493 | } |
||
494 | |||
495 | static int test_leave_db_mutex( |
||
496 | object clientdata, |
||
497 | Tcl_Interp interp, |
||
498 | int objc, |
||
499 | Tcl_Obj[] objv |
||
500 | ) |
||
501 | { |
||
502 | sqlite3 db = null; |
||
503 | if ( objc != 2 ) |
||
504 | { |
||
505 | TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB" ); |
||
506 | return TCL.TCL_ERROR; |
||
507 | } |
||
508 | getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ); |
||
509 | if ( null == db ) |
||
510 | { |
||
511 | return TCL.TCL_ERROR; |
||
512 | } |
||
513 | sqlite3_mutex_leave( sqlite3_db_mutex( db ) ); |
||
514 | return TCL.TCL_OK; |
||
515 | } |
||
516 | |||
517 | static public int Sqlitetest_mutex_Init( Tcl_Interp interp ) |
||
518 | { |
||
519 | //static struct { |
||
520 | // string zName; |
||
521 | // Tcl_ObjCmdProc *xProc; |
||
522 | //} |
||
523 | _aObjCmd[] aCmd = new _aObjCmd[]{ |
||
524 | new _aObjCmd( "sqlite3_shutdown", test_shutdown ), |
||
525 | new _aObjCmd( "sqlite3_initialize", test_initialize ), |
||
526 | new _aObjCmd( "sqlite3_config", test_config ), |
||
527 | |||
528 | new _aObjCmd("enter_db_mutex", test_enter_db_mutex ), |
||
529 | new _aObjCmd( "leave_db_mutex", test_leave_db_mutex ), |
||
530 | |||
531 | new _aObjCmd( "alloc_dealloc_mutex", test_alloc_mutex ), |
||
532 | new _aObjCmd( "install_mutex_counters", test_install_mutex_counters ), |
||
533 | new _aObjCmd( "read_mutex_counters", test_read_mutex_counters ), |
||
534 | new _aObjCmd( "clear_mutex_counters", test_clear_mutex_counters ), |
||
535 | }; |
||
536 | int i; |
||
537 | for ( i = 0; i < aCmd.Length; i++ ) |
||
538 | {//sizeof(aCmd)/sizeof(aCmd[0]); i++){ |
||
539 | TCL.Tcl_CreateObjCommand( interp, aCmd[i].zName, aCmd[i].xProc, null, null ); |
||
540 | } |
||
541 | |||
542 | TCL.Tcl_LinkVar(interp, "disable_mutex_init",disableInit, VarFlags.SQLITE3_LINK_INT ); |
||
543 | //g.disableInit, VarFlags.SQLITE3_LINK_INT ); |
||
544 | TCL.Tcl_LinkVar( interp, "disable_mutex_try",disableTry, VarFlags.SQLITE3_LINK_INT ); |
||
545 | //g.disableTry, VarFlags.SQLITE3_LINK_INT ); |
||
546 | return SQLITE_OK; |
||
547 | } |
||
548 | } |
||
549 | #endif |
||
550 | } |