| 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 |