modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/test_async.c (about)

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