| OLD | NEW |
| 1 /* | 1 /* |
| 2 ** 2007 September 9 | 2 ** 2007 September 9 |
| 3 ** | 3 ** |
| 4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
| 5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
| 6 ** | 6 ** |
| 7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
| 8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
| 9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
| 10 ** | 10 ** |
| 11 ************************************************************************* | 11 ************************************************************************* |
| 12 ** | 12 ** |
| 13 ** This file contains the implementation of some Tcl commands used to | 13 ** This file contains the implementation of some Tcl commands used to |
| 14 ** test that sqlite3 database handles may be concurrently accessed by | 14 ** test that sqlite3 database handles may be concurrently accessed by |
| 15 ** multiple threads. Right now this only works on unix. | 15 ** multiple threads. Right now this only works on unix. |
| 16 ** | |
| 17 ** $Id: test_thread.c,v 1.15 2009/03/27 12:32:56 drh Exp $ | |
| 18 */ | 16 */ |
| 19 | 17 |
| 20 #include "sqliteInt.h" | 18 #include "sqliteInt.h" |
| 21 #include <tcl.h> | 19 #include <tcl.h> |
| 22 | 20 |
| 23 #if SQLITE_THREADSAFE | 21 #if SQLITE_THREADSAFE |
| 24 | 22 |
| 25 #include <errno.h> | 23 #include <errno.h> |
| 26 | 24 |
| 27 #if !defined(_MSC_VER) | 25 #if !defined(_MSC_VER) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 48 */ | 46 */ |
| 49 typedef struct EvalEvent EvalEvent; | 47 typedef struct EvalEvent EvalEvent; |
| 50 struct EvalEvent { | 48 struct EvalEvent { |
| 51 Tcl_Event base; /* Base class of type Tcl_Event */ | 49 Tcl_Event base; /* Base class of type Tcl_Event */ |
| 52 char *zScript; /* The script to execute. */ | 50 char *zScript; /* The script to execute. */ |
| 53 Tcl_Interp *interp; /* The interpreter to execute it in. */ | 51 Tcl_Interp *interp; /* The interpreter to execute it in. */ |
| 54 }; | 52 }; |
| 55 | 53 |
| 56 static Tcl_ObjCmdProc sqlthread_proc; | 54 static Tcl_ObjCmdProc sqlthread_proc; |
| 57 static Tcl_ObjCmdProc clock_seconds_proc; | 55 static Tcl_ObjCmdProc clock_seconds_proc; |
| 58 #if defined(SQLITE_OS_UNIX) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) | 56 #if SQLITE_OS_UNIX && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) |
| 59 static Tcl_ObjCmdProc blocking_step_proc; | 57 static Tcl_ObjCmdProc blocking_step_proc; |
| 60 static Tcl_ObjCmdProc blocking_prepare_v2_proc; | 58 static Tcl_ObjCmdProc blocking_prepare_v2_proc; |
| 61 #endif | 59 #endif |
| 62 int Sqlitetest1_Init(Tcl_Interp *); | 60 int Sqlitetest1_Init(Tcl_Interp *); |
| 61 int Sqlite3_Init(Tcl_Interp *); |
| 63 | 62 |
| 64 /* Functions from test1.c */ | 63 /* Functions from test1.c */ |
| 65 void *sqlite3TestTextToPtr(const char *); | 64 void *sqlite3TestTextToPtr(const char *); |
| 66 const char *sqlite3TestErrorName(int); | 65 const char *sqlite3TestErrorName(int); |
| 67 int getDbPointer(Tcl_Interp *, const char *, sqlite3 **); | 66 int getDbPointer(Tcl_Interp *, const char *, sqlite3 **); |
| 68 int sqlite3TestMakePointerStr(Tcl_Interp *, char *, void *); | 67 int sqlite3TestMakePointerStr(Tcl_Interp *, char *, void *); |
| 69 int sqlite3TestErrCode(Tcl_Interp *, sqlite3 *, int); | 68 int sqlite3TestErrCode(Tcl_Interp *, sqlite3 *, int); |
| 70 | 69 |
| 71 /* | 70 /* |
| 72 ** Handler for events of type EvalEvent. | 71 ** Handler for events of type EvalEvent. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 Tcl_Interp *interp; | 109 Tcl_Interp *interp; |
| 111 Tcl_Obj *pRes; | 110 Tcl_Obj *pRes; |
| 112 Tcl_Obj *pList; | 111 Tcl_Obj *pList; |
| 113 int rc; | 112 int rc; |
| 114 SqlThread *p = (SqlThread *)pSqlThread; | 113 SqlThread *p = (SqlThread *)pSqlThread; |
| 115 extern int Sqlitetest_mutex_Init(Tcl_Interp*); | 114 extern int Sqlitetest_mutex_Init(Tcl_Interp*); |
| 116 | 115 |
| 117 interp = Tcl_CreateInterp(); | 116 interp = Tcl_CreateInterp(); |
| 118 Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0); | 117 Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0); |
| 119 Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, pSqlThread, 0); | 118 Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, pSqlThread, 0); |
| 120 #if defined(SQLITE_OS_UNIX) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) | 119 #if SQLITE_OS_UNIX && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) |
| 121 Tcl_CreateObjCommand(interp, "sqlite3_blocking_step", blocking_step_proc,0,0); | 120 Tcl_CreateObjCommand(interp, "sqlite3_blocking_step", blocking_step_proc,0,0); |
| 122 Tcl_CreateObjCommand(interp, | 121 Tcl_CreateObjCommand(interp, |
| 123 "sqlite3_blocking_prepare_v2", blocking_prepare_v2_proc, (void *)1, 0); | 122 "sqlite3_blocking_prepare_v2", blocking_prepare_v2_proc, (void *)1, 0); |
| 124 Tcl_CreateObjCommand(interp, | 123 Tcl_CreateObjCommand(interp, |
| 125 "sqlite3_nonblocking_prepare_v2", blocking_prepare_v2_proc, 0, 0); | 124 "sqlite3_nonblocking_prepare_v2", blocking_prepare_v2_proc, 0, 0); |
| 126 #endif | 125 #endif |
| 127 Sqlitetest1_Init(interp); | 126 Sqlitetest1_Init(interp); |
| 128 Sqlitetest_mutex_Init(interp); | 127 Sqlitetest_mutex_Init(interp); |
| 128 Sqlite3_Init(interp); |
| 129 | 129 |
| 130 rc = Tcl_Eval(interp, p->zScript); | 130 rc = Tcl_Eval(interp, p->zScript); |
| 131 pRes = Tcl_GetObjResult(interp); | 131 pRes = Tcl_GetObjResult(interp); |
| 132 pList = Tcl_NewObj(); | 132 pList = Tcl_NewObj(); |
| 133 Tcl_IncrRefCount(pList); | 133 Tcl_IncrRefCount(pList); |
| 134 Tcl_IncrRefCount(pRes); | 134 Tcl_IncrRefCount(pRes); |
| 135 | 135 |
| 136 if( rc!=TCL_OK ){ | 136 if( rc!=TCL_OK ){ |
| 137 Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj("error", -1)); | 137 Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj("error", -1)); |
| 138 Tcl_ListObjAppendElement(interp, pList, pRes); | 138 Tcl_ListObjAppendElement(interp, pList, pRes); |
| 139 postToParent(p, pList); | 139 postToParent(p, pList); |
| 140 Tcl_DecrRefCount(pList); | 140 Tcl_DecrRefCount(pList); |
| 141 pList = Tcl_NewObj(); | 141 pList = Tcl_NewObj(); |
| 142 } | 142 } |
| 143 | 143 |
| 144 Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj("set", -1)); | 144 Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj("set", -1)); |
| 145 Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj(p->zVarname, -1)); | 145 Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj(p->zVarname, -1)); |
| 146 Tcl_ListObjAppendElement(interp, pList, pRes); | 146 Tcl_ListObjAppendElement(interp, pList, pRes); |
| 147 postToParent(p, pList); | 147 postToParent(p, pList); |
| 148 | 148 |
| 149 ckfree((void *)p); | 149 ckfree((void *)p); |
| 150 Tcl_DecrRefCount(pList); | 150 Tcl_DecrRefCount(pList); |
| 151 Tcl_DecrRefCount(pRes); | 151 Tcl_DecrRefCount(pRes); |
| 152 Tcl_DeleteInterp(interp); | 152 Tcl_DeleteInterp(interp); |
| 153 while( Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT) ); |
| 154 Tcl_ExitThread(0); |
| 153 TCL_THREAD_CREATE_RETURN; | 155 TCL_THREAD_CREATE_RETURN; |
| 154 } | 156 } |
| 155 | 157 |
| 156 /* | 158 /* |
| 157 ** sqlthread spawn VARNAME SCRIPT | 159 ** sqlthread spawn VARNAME SCRIPT |
| 158 ** | 160 ** |
| 159 ** Spawn a new thread with its own Tcl interpreter and run the | 161 ** Spawn a new thread with its own Tcl interpreter and run the |
| 160 ** specified SCRIPT(s) in it. The thread terminates after running | 162 ** specified SCRIPT(s) in it. The thread terminates after running |
| 161 ** the script. The result of the script is stored in the variable | 163 ** the script. The result of the script is stored in the variable |
| 162 ** VARNAME. | 164 ** VARNAME. |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 ** is only available on UNIX for now. This is because pthread condition | 385 ** is only available on UNIX for now. This is because pthread condition |
| 384 ** variables are used. | 386 ** variables are used. |
| 385 ** | 387 ** |
| 386 ** The source code for the C functions sqlite3_blocking_step(), | 388 ** The source code for the C functions sqlite3_blocking_step(), |
| 387 ** blocking_step_notify() and the structure UnlockNotification is | 389 ** blocking_step_notify() and the structure UnlockNotification is |
| 388 ** automatically extracted from this file and used as part of the | 390 ** automatically extracted from this file and used as part of the |
| 389 ** documentation for the sqlite3_unlock_notify() API function. This | 391 ** documentation for the sqlite3_unlock_notify() API function. This |
| 390 ** should be considered if these functions are to be extended (i.e. to | 392 ** should be considered if these functions are to be extended (i.e. to |
| 391 ** support windows) in the future. | 393 ** support windows) in the future. |
| 392 */ | 394 */ |
| 393 #if defined(SQLITE_OS_UNIX) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) | 395 #if SQLITE_OS_UNIX && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) |
| 394 | 396 |
| 395 /* BEGIN_SQLITE_BLOCKING_STEP */ | 397 /* BEGIN_SQLITE_BLOCKING_STEP */ |
| 396 /* This example uses the pthreads API */ | 398 /* This example uses the pthreads API */ |
| 397 #include <pthread.h> | 399 #include <pthread.h> |
| 398 | 400 |
| 399 /* | 401 /* |
| 400 ** A pointer to an instance of this structure is passed as the user-context | 402 ** A pointer to an instance of this structure is passed as the user-context |
| 401 ** pointer when registering for an unlock-notify callback. | 403 ** pointer when registering for an unlock-notify callback. |
| 402 */ | 404 */ |
| 403 typedef struct UnlockNotification UnlockNotification; | 405 typedef struct UnlockNotification UnlockNotification; |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 /* | 607 /* |
| 606 ** End of implementation of [sqlite3_blocking_step]. | 608 ** End of implementation of [sqlite3_blocking_step]. |
| 607 ************************************************************************/ | 609 ************************************************************************/ |
| 608 | 610 |
| 609 /* | 611 /* |
| 610 ** Register commands with the TCL interpreter. | 612 ** Register commands with the TCL interpreter. |
| 611 */ | 613 */ |
| 612 int SqlitetestThread_Init(Tcl_Interp *interp){ | 614 int SqlitetestThread_Init(Tcl_Interp *interp){ |
| 613 Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, 0, 0); | 615 Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, 0, 0); |
| 614 Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0); | 616 Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0); |
| 615 #if defined(SQLITE_OS_UNIX) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) | 617 #if SQLITE_OS_UNIX && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) |
| 616 Tcl_CreateObjCommand(interp, "sqlite3_blocking_step", blocking_step_proc,0,0); | 618 Tcl_CreateObjCommand(interp, "sqlite3_blocking_step", blocking_step_proc,0,0); |
| 617 Tcl_CreateObjCommand(interp, | 619 Tcl_CreateObjCommand(interp, |
| 618 "sqlite3_blocking_prepare_v2", blocking_prepare_v2_proc, (void *)1, 0); | 620 "sqlite3_blocking_prepare_v2", blocking_prepare_v2_proc, (void *)1, 0); |
| 619 Tcl_CreateObjCommand(interp, | 621 Tcl_CreateObjCommand(interp, |
| 620 "sqlite3_nonblocking_prepare_v2", blocking_prepare_v2_proc, 0, 0); | 622 "sqlite3_nonblocking_prepare_v2", blocking_prepare_v2_proc, 0, 0); |
| 621 #endif | 623 #endif |
| 622 return TCL_OK; | 624 return TCL_OK; |
| 623 } | 625 } |
| 624 #else | 626 #else |
| 625 int SqlitetestThread_Init(Tcl_Interp *interp){ | 627 int SqlitetestThread_Init(Tcl_Interp *interp){ |
| 626 return TCL_OK; | 628 return TCL_OK; |
| 627 } | 629 } |
| 628 #endif | 630 #endif |
| OLD | NEW |