| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 ** 2005 December 14 | |
| 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 ** | |
| 13 ** $Id: test_async.c,v 1.62 2009/04/28 13:01:09 drh Exp $ | |
| 14 ** | |
| 15 ** This file contains a binding of the asynchronous IO extension interface | |
| 16 ** (defined in ext/async/sqlite3async.h) to Tcl. | |
| 17 */ | |
| 18 | |
| 19 #define TCL_THREADS | |
| 20 #include <tcl.h> | |
| 21 | |
| 22 #ifdef SQLITE_ENABLE_ASYNCIO | |
| 23 | |
| 24 #include "sqlite3async.h" | |
| 25 #include "sqlite3.h" | |
| 26 #include <assert.h> | |
| 27 | |
| 28 /* From test1.c */ | |
| 29 const char *sqlite3TestErrorName(int); | |
| 30 | |
| 31 | |
| 32 struct TestAsyncGlobal { | |
| 33 int isInstalled; /* True when async VFS is installed */ | |
| 34 } testasync_g = { 0 }; | |
| 35 | |
| 36 TCL_DECLARE_MUTEX(testasync_g_writerMutex); | |
| 37 | |
| 38 /* | |
| 39 ** sqlite3async_initialize PARENT-VFS ISDEFAULT | |
| 40 */ | |
| 41 static int testAsyncInit( | |
| 42 void * clientData, | |
| 43 Tcl_Interp *interp, | |
| 44 int objc, | |
| 45 Tcl_Obj *CONST objv[] | |
| 46 ){ | |
| 47 const char *zParent; | |
| 48 int isDefault; | |
| 49 int rc; | |
| 50 | |
| 51 if( objc!=3 ){ | |
| 52 Tcl_WrongNumArgs(interp, 1, objv, "PARENT-VFS ISDEFAULT"); | |
| 53 return TCL_ERROR; | |
| 54 } | |
| 55 zParent = Tcl_GetString(objv[1]); | |
| 56 if( !*zParent ) { | |
| 57 zParent = 0; | |
| 58 } | |
| 59 if( Tcl_GetBooleanFromObj(interp, objv[2], &isDefault) ){ | |
| 60 return TCL_ERROR; | |
| 61 } | |
| 62 | |
| 63 rc = sqlite3async_initialize(zParent, isDefault); | |
| 64 if( rc!=SQLITE_OK ){ | |
| 65 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3TestErrorName(rc), -1)); | |
| 66 return TCL_ERROR; | |
| 67 } | |
| 68 return TCL_OK; | |
| 69 } | |
| 70 | |
| 71 /* | |
| 72 ** sqlite3async_shutdown | |
| 73 */ | |
| 74 static int testAsyncShutdown( | |
| 75 void * clientData, | |
| 76 Tcl_Interp *interp, | |
| 77 int objc, | |
| 78 Tcl_Obj *CONST objv[] | |
| 79 ){ | |
| 80 sqlite3async_shutdown(); | |
| 81 return TCL_OK; | |
| 82 } | |
| 83 | |
| 84 static Tcl_ThreadCreateType tclWriterThread(ClientData pIsStarted){ | |
| 85 Tcl_MutexLock(&testasync_g_writerMutex); | |
| 86 *((int *)pIsStarted) = 1; | |
| 87 sqlite3async_run(); | |
| 88 Tcl_MutexUnlock(&testasync_g_writerMutex); | |
| 89 TCL_THREAD_CREATE_RETURN; | |
| 90 } | |
| 91 | |
| 92 /* | |
| 93 ** sqlite3async_start | |
| 94 ** | |
| 95 ** Start a new writer thread. | |
| 96 */ | |
| 97 static int testAsyncStart( | |
| 98 void * clientData, | |
| 99 Tcl_Interp *interp, | |
| 100 int objc, | |
| 101 Tcl_Obj *CONST objv[] | |
| 102 ){ | |
| 103 volatile int isStarted = 0; | |
| 104 ClientData threadData = (ClientData)&isStarted; | |
| 105 | |
| 106 Tcl_ThreadId x; | |
| 107 const int nStack = TCL_THREAD_STACK_DEFAULT; | |
| 108 const int flags = TCL_THREAD_NOFLAGS; | |
| 109 int rc; | |
| 110 | |
| 111 rc = Tcl_CreateThread(&x, tclWriterThread, threadData, nStack, flags); | |
| 112 if( rc!=TCL_OK ){ | |
| 113 Tcl_AppendResult(interp, "Tcl_CreateThread() failed", 0); | |
| 114 return TCL_ERROR; | |
| 115 } | |
| 116 | |
| 117 while( isStarted==0 ) { /* Busy loop */ } | |
| 118 return TCL_OK; | |
| 119 } | |
| 120 | |
| 121 /* | |
| 122 ** sqlite3async_wait | |
| 123 ** | |
| 124 ** Wait for the current writer thread to terminate. | |
| 125 ** | |
| 126 ** If the current writer thread is set to run forever then this | |
| 127 ** command would block forever. To prevent that, an error is returned. | |
| 128 */ | |
| 129 static int testAsyncWait( | |
| 130 void * clientData, | |
| 131 Tcl_Interp *interp, | |
| 132 int objc, | |
| 133 Tcl_Obj *CONST objv[] | |
| 134 ){ | |
| 135 int eCond; | |
| 136 if( objc!=1 ){ | |
| 137 Tcl_WrongNumArgs(interp, 1, objv, ""); | |
| 138 return TCL_ERROR; | |
| 139 } | |
| 140 | |
| 141 sqlite3async_control(SQLITEASYNC_GET_HALT, &eCond); | |
| 142 if( eCond==SQLITEASYNC_HALT_NEVER ){ | |
| 143 Tcl_AppendResult(interp, "would block forever", (char*)0); | |
| 144 return TCL_ERROR; | |
| 145 } | |
| 146 | |
| 147 Tcl_MutexLock(&testasync_g_writerMutex); | |
| 148 Tcl_MutexUnlock(&testasync_g_writerMutex); | |
| 149 return TCL_OK; | |
| 150 } | |
| 151 | |
| 152 /* | |
| 153 ** sqlite3async_control OPTION ?VALUE? | |
| 154 */ | |
| 155 static int testAsyncControl( | |
| 156 void * clientData, | |
| 157 Tcl_Interp *interp, | |
| 158 int objc, | |
| 159 Tcl_Obj *CONST objv[] | |
| 160 ){ | |
| 161 int rc = SQLITE_OK; | |
| 162 int aeOpt[] = { SQLITEASYNC_HALT, SQLITEASYNC_DELAY, SQLITEASYNC_LOCKFILES }; | |
| 163 const char *azOpt[] = { "halt", "delay", "lockfiles", 0 }; | |
| 164 const char *az[] = { "never", "now", "idle", 0 }; | |
| 165 int iVal; | |
| 166 int eOpt; | |
| 167 | |
| 168 if( objc!=2 && objc!=3 ){ | |
| 169 Tcl_WrongNumArgs(interp, 1, objv, "OPTION ?VALUE?"); | |
| 170 return TCL_ERROR; | |
| 171 } | |
| 172 if( Tcl_GetIndexFromObj(interp, objv[1], azOpt, "option", 0, &eOpt) ){ | |
| 173 return TCL_ERROR; | |
| 174 } | |
| 175 eOpt = aeOpt[eOpt]; | |
| 176 | |
| 177 if( objc==3 ){ | |
| 178 switch( eOpt ){ | |
| 179 case SQLITEASYNC_HALT: { | |
| 180 assert( SQLITEASYNC_HALT_NEVER==0 ); | |
| 181 assert( SQLITEASYNC_HALT_NOW==1 ); | |
| 182 assert( SQLITEASYNC_HALT_IDLE==2 ); | |
| 183 if( Tcl_GetIndexFromObj(interp, objv[2], az, "value", 0, &iVal) ){ | |
| 184 return TCL_ERROR; | |
| 185 } | |
| 186 break; | |
| 187 } | |
| 188 case SQLITEASYNC_DELAY: | |
| 189 if( Tcl_GetIntFromObj(interp, objv[2], &iVal) ){ | |
| 190 return TCL_ERROR; | |
| 191 } | |
| 192 break; | |
| 193 | |
| 194 case SQLITEASYNC_LOCKFILES: | |
| 195 if( Tcl_GetBooleanFromObj(interp, objv[2], &iVal) ){ | |
| 196 return TCL_ERROR; | |
| 197 } | |
| 198 break; | |
| 199 } | |
| 200 | |
| 201 rc = sqlite3async_control(eOpt, iVal); | |
| 202 } | |
| 203 | |
| 204 if( rc==SQLITE_OK ){ | |
| 205 rc = sqlite3async_control( | |
| 206 eOpt==SQLITEASYNC_HALT ? SQLITEASYNC_GET_HALT : | |
| 207 eOpt==SQLITEASYNC_DELAY ? SQLITEASYNC_GET_DELAY : | |
| 208 SQLITEASYNC_GET_LOCKFILES, &iVal); | |
| 209 } | |
| 210 | |
| 211 if( rc!=SQLITE_OK ){ | |
| 212 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3TestErrorName(rc), -1)); | |
| 213 return TCL_ERROR; | |
| 214 } | |
| 215 | |
| 216 if( eOpt==SQLITEASYNC_HALT ){ | |
| 217 Tcl_SetObjResult(interp, Tcl_NewStringObj(az[iVal], -1)); | |
| 218 }else{ | |
| 219 Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal)); | |
| 220 } | |
| 221 | |
| 222 return TCL_OK; | |
| 223 } | |
| 224 | |
| 225 #endif /* SQLITE_ENABLE_ASYNCIO */ | |
| 226 | |
| 227 /* | |
| 228 ** This routine registers the custom TCL commands defined in this | |
| 229 ** module. This should be the only procedure visible from outside | |
| 230 ** of this module. | |
| 231 */ | |
| 232 int Sqlitetestasync_Init(Tcl_Interp *interp){ | |
| 233 #if SQLITE_ENABLE_ASYNCIO | |
| 234 Tcl_CreateObjCommand(interp,"sqlite3async_start",testAsyncStart,0,0); | |
| 235 Tcl_CreateObjCommand(interp,"sqlite3async_wait",testAsyncWait,0,0); | |
| 236 | |
| 237 Tcl_CreateObjCommand(interp,"sqlite3async_control",testAsyncControl,0,0); | |
| 238 Tcl_CreateObjCommand(interp,"sqlite3async_initialize",testAsyncInit,0,0); | |
| 239 Tcl_CreateObjCommand(interp,"sqlite3async_shutdown",testAsyncShutdown,0,0); | |
| 240 #endif /* SQLITE_ENABLE_ASYNCIO */ | |
| 241 return TCL_OK; | |
| 242 } | |
| OLD | NEW |