xref: /sqlite-3.40.0/src/test_async.c (revision 7617e4a8)
12366940dSdrh /*
22366940dSdrh ** 2005 December 14
32366940dSdrh **
42366940dSdrh ** The author disclaims copyright to this source code.  In place of
52366940dSdrh ** a legal notice, here is a blessing:
62366940dSdrh **
72366940dSdrh **    May you do good and not evil.
82366940dSdrh **    May you find forgiveness for yourself and forgive others.
92366940dSdrh **    May you share freely, never taking more than you give.
102366940dSdrh **
112366940dSdrh *************************************************************************
122366940dSdrh **
13a3f06598Sdanielk1977 ** This file contains a binding of the asynchronous IO extension interface
14a3f06598Sdanielk1977 ** (defined in ext/async/sqlite3async.h) to Tcl.
157eda2cdbSdanielk1977 */
167eda2cdbSdanielk1977 
17a3f06598Sdanielk1977 #define TCL_THREADS
1852b1dbb5Smistachkin #if defined(INCLUDE_SQLITE_TCL_H)
1952b1dbb5Smistachkin #  include "sqlite_tcl.h"
2052b1dbb5Smistachkin #else
2152b1dbb5Smistachkin #  include "tcl.h"
22*7617e4a8Smistachkin #  ifndef SQLITE_TCLAPI
23*7617e4a8Smistachkin #    define SQLITE_TCLAPI
24*7617e4a8Smistachkin #  endif
2552b1dbb5Smistachkin #endif
262366940dSdrh 
27a3f06598Sdanielk1977 #ifdef SQLITE_ENABLE_ASYNCIO
282366940dSdrh 
29a3f06598Sdanielk1977 #include "sqlite3async.h"
30a3f06598Sdanielk1977 #include "sqlite3.h"
31a3f06598Sdanielk1977 #include <assert.h>
322366940dSdrh 
33e84d8d32Smistachkin /* From main.c */
34e84d8d32Smistachkin extern const char *sqlite3ErrName(int);
356f050aa2Sdanielk1977 
362366940dSdrh 
37a3f06598Sdanielk1977 struct TestAsyncGlobal {
38a3f06598Sdanielk1977   int isInstalled;                     /* True when async VFS is installed */
39a3f06598Sdanielk1977 } testasync_g = { 0 };
402366940dSdrh 
41a3f06598Sdanielk1977 TCL_DECLARE_MUTEX(testasync_g_writerMutex);
422366940dSdrh 
432366940dSdrh /*
446f050aa2Sdanielk1977 ** sqlite3async_initialize PARENT-VFS ISDEFAULT
452366940dSdrh */
testAsyncInit(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])46*7617e4a8Smistachkin static int SQLITE_TCLAPI testAsyncInit(
472366940dSdrh   void * clientData,
482366940dSdrh   Tcl_Interp *interp,
492366940dSdrh   int objc,
502366940dSdrh   Tcl_Obj *CONST objv[]
512366940dSdrh ){
526f050aa2Sdanielk1977   const char *zParent;
536f050aa2Sdanielk1977   int isDefault;
546f050aa2Sdanielk1977   int rc;
556f050aa2Sdanielk1977 
566f050aa2Sdanielk1977   if( objc!=3 ){
576f050aa2Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "PARENT-VFS ISDEFAULT");
582366940dSdrh     return TCL_ERROR;
592366940dSdrh   }
606f050aa2Sdanielk1977   zParent = Tcl_GetString(objv[1]);
616f050aa2Sdanielk1977   if( !*zParent ) {
626f050aa2Sdanielk1977     zParent = 0;
636f050aa2Sdanielk1977   }
646f050aa2Sdanielk1977   if( Tcl_GetBooleanFromObj(interp, objv[2], &isDefault) ){
656f050aa2Sdanielk1977     return TCL_ERROR;
666f050aa2Sdanielk1977   }
676f050aa2Sdanielk1977 
686f050aa2Sdanielk1977   rc = sqlite3async_initialize(zParent, isDefault);
696f050aa2Sdanielk1977   if( rc!=SQLITE_OK ){
70e84d8d32Smistachkin     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
716f050aa2Sdanielk1977     return TCL_ERROR;
726f050aa2Sdanielk1977   }
736f050aa2Sdanielk1977   return TCL_OK;
746f050aa2Sdanielk1977 }
756f050aa2Sdanielk1977 
766f050aa2Sdanielk1977 /*
776f050aa2Sdanielk1977 ** sqlite3async_shutdown
786f050aa2Sdanielk1977 */
testAsyncShutdown(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])79*7617e4a8Smistachkin static int SQLITE_TCLAPI testAsyncShutdown(
806f050aa2Sdanielk1977   void * clientData,
816f050aa2Sdanielk1977   Tcl_Interp *interp,
826f050aa2Sdanielk1977   int objc,
836f050aa2Sdanielk1977   Tcl_Obj *CONST objv[]
846f050aa2Sdanielk1977 ){
85a3f06598Sdanielk1977   sqlite3async_shutdown();
862366940dSdrh   return TCL_OK;
872366940dSdrh }
882366940dSdrh 
tclWriterThread(ClientData pIsStarted)89a3f06598Sdanielk1977 static Tcl_ThreadCreateType tclWriterThread(ClientData pIsStarted){
90a3f06598Sdanielk1977   Tcl_MutexLock(&testasync_g_writerMutex);
91a3f06598Sdanielk1977   *((int *)pIsStarted) = 1;
92a3f06598Sdanielk1977   sqlite3async_run();
93a3f06598Sdanielk1977   Tcl_MutexUnlock(&testasync_g_writerMutex);
943374f8aeSdan   Tcl_ExitThread(0);
95a3f06598Sdanielk1977   TCL_THREAD_CREATE_RETURN;
96a3f06598Sdanielk1977 }
97a3f06598Sdanielk1977 
982366940dSdrh /*
992366940dSdrh ** sqlite3async_start
1002366940dSdrh **
1012366940dSdrh ** Start a new writer thread.
1022366940dSdrh */
testAsyncStart(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])103*7617e4a8Smistachkin static int SQLITE_TCLAPI testAsyncStart(
1042366940dSdrh   void * clientData,
1052366940dSdrh   Tcl_Interp *interp,
1062366940dSdrh   int objc,
1072366940dSdrh   Tcl_Obj *CONST objv[]
1082366940dSdrh ){
1095be7d5d1Sdanielk1977   volatile int isStarted = 0;
110a3f06598Sdanielk1977   ClientData threadData = (ClientData)&isStarted;
111a3f06598Sdanielk1977 
112a3f06598Sdanielk1977   Tcl_ThreadId x;
113a3f06598Sdanielk1977   const int nStack = TCL_THREAD_STACK_DEFAULT;
114a3f06598Sdanielk1977   const int flags = TCL_THREAD_NOFLAGS;
115a3f06598Sdanielk1977   int rc;
116a3f06598Sdanielk1977 
117a3f06598Sdanielk1977   rc = Tcl_CreateThread(&x, tclWriterThread, threadData, nStack, flags);
118a3f06598Sdanielk1977   if( rc!=TCL_OK ){
1194598b8e4Sdanielk1977     Tcl_AppendResult(interp, "Tcl_CreateThread() failed", 0);
1202366940dSdrh     return TCL_ERROR;
1212366940dSdrh   }
1224598b8e4Sdanielk1977 
1234598b8e4Sdanielk1977   while( isStarted==0 ) { /* Busy loop */ }
1242366940dSdrh   return TCL_OK;
1252366940dSdrh }
1262366940dSdrh 
1272366940dSdrh /*
1282366940dSdrh ** sqlite3async_wait
1292366940dSdrh **
1302366940dSdrh ** Wait for the current writer thread to terminate.
1312366940dSdrh **
1322366940dSdrh ** If the current writer thread is set to run forever then this
1332366940dSdrh ** command would block forever.  To prevent that, an error is returned.
1342366940dSdrh */
testAsyncWait(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])135*7617e4a8Smistachkin static int SQLITE_TCLAPI testAsyncWait(
1362366940dSdrh   void * clientData,
1372366940dSdrh   Tcl_Interp *interp,
1382366940dSdrh   int objc,
1392366940dSdrh   Tcl_Obj *CONST objv[]
1402366940dSdrh ){
141a3f06598Sdanielk1977   int eCond;
142a3f06598Sdanielk1977   if( objc!=1 ){
143a3f06598Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
144a3f06598Sdanielk1977     return TCL_ERROR;
145a3f06598Sdanielk1977   }
146a3f06598Sdanielk1977 
147a3f06598Sdanielk1977   sqlite3async_control(SQLITEASYNC_GET_HALT, &eCond);
148a3f06598Sdanielk1977   if( eCond==SQLITEASYNC_HALT_NEVER ){
1492366940dSdrh     Tcl_AppendResult(interp, "would block forever", (char*)0);
1502366940dSdrh     return TCL_ERROR;
1512366940dSdrh   }
152750b03e5Sdanielk1977 
153a3f06598Sdanielk1977   Tcl_MutexLock(&testasync_g_writerMutex);
154a3f06598Sdanielk1977   Tcl_MutexUnlock(&testasync_g_writerMutex);
1552366940dSdrh   return TCL_OK;
1562366940dSdrh }
1572366940dSdrh 
1586f050aa2Sdanielk1977 /*
1596f050aa2Sdanielk1977 ** sqlite3async_control OPTION ?VALUE?
1606f050aa2Sdanielk1977 */
testAsyncControl(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])161*7617e4a8Smistachkin static int SQLITE_TCLAPI testAsyncControl(
1626f050aa2Sdanielk1977   void * clientData,
1636f050aa2Sdanielk1977   Tcl_Interp *interp,
1646f050aa2Sdanielk1977   int objc,
1656f050aa2Sdanielk1977   Tcl_Obj *CONST objv[]
1666f050aa2Sdanielk1977 ){
1676f050aa2Sdanielk1977   int rc = SQLITE_OK;
1686f050aa2Sdanielk1977   int aeOpt[] = { SQLITEASYNC_HALT, SQLITEASYNC_DELAY, SQLITEASYNC_LOCKFILES };
1696f050aa2Sdanielk1977   const char *azOpt[] = { "halt", "delay", "lockfiles", 0 };
1706f050aa2Sdanielk1977   const char *az[] = { "never", "now", "idle", 0 };
1716f050aa2Sdanielk1977   int iVal;
1726f050aa2Sdanielk1977   int eOpt;
1736f050aa2Sdanielk1977 
1746f050aa2Sdanielk1977   if( objc!=2 && objc!=3 ){
1756f050aa2Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "OPTION ?VALUE?");
1766f050aa2Sdanielk1977     return TCL_ERROR;
1776f050aa2Sdanielk1977   }
1786f050aa2Sdanielk1977   if( Tcl_GetIndexFromObj(interp, objv[1], azOpt, "option", 0, &eOpt) ){
1796f050aa2Sdanielk1977     return TCL_ERROR;
1806f050aa2Sdanielk1977   }
1816f050aa2Sdanielk1977   eOpt = aeOpt[eOpt];
1826f050aa2Sdanielk1977 
1836f050aa2Sdanielk1977   if( objc==3 ){
1846f050aa2Sdanielk1977     switch( eOpt ){
1856f050aa2Sdanielk1977       case SQLITEASYNC_HALT: {
1866f050aa2Sdanielk1977         assert( SQLITEASYNC_HALT_NEVER==0 );
1876f050aa2Sdanielk1977         assert( SQLITEASYNC_HALT_NOW==1 );
1886f050aa2Sdanielk1977         assert( SQLITEASYNC_HALT_IDLE==2 );
1896f050aa2Sdanielk1977         if( Tcl_GetIndexFromObj(interp, objv[2], az, "value", 0, &iVal) ){
1906f050aa2Sdanielk1977           return TCL_ERROR;
1916f050aa2Sdanielk1977         }
1926f050aa2Sdanielk1977         break;
1936f050aa2Sdanielk1977       }
1946f050aa2Sdanielk1977       case SQLITEASYNC_DELAY:
1956f050aa2Sdanielk1977         if( Tcl_GetIntFromObj(interp, objv[2], &iVal) ){
1966f050aa2Sdanielk1977           return TCL_ERROR;
1976f050aa2Sdanielk1977         }
1986f050aa2Sdanielk1977         break;
1996f050aa2Sdanielk1977 
2006f050aa2Sdanielk1977       case SQLITEASYNC_LOCKFILES:
2016f050aa2Sdanielk1977         if( Tcl_GetBooleanFromObj(interp, objv[2], &iVal) ){
2026f050aa2Sdanielk1977           return TCL_ERROR;
2036f050aa2Sdanielk1977         }
2046f050aa2Sdanielk1977         break;
2056f050aa2Sdanielk1977     }
2066f050aa2Sdanielk1977 
2076f050aa2Sdanielk1977     rc = sqlite3async_control(eOpt, iVal);
2086f050aa2Sdanielk1977   }
2096f050aa2Sdanielk1977 
2106f050aa2Sdanielk1977   if( rc==SQLITE_OK ){
2116f050aa2Sdanielk1977     rc = sqlite3async_control(
2126f050aa2Sdanielk1977         eOpt==SQLITEASYNC_HALT ? SQLITEASYNC_GET_HALT :
2136f050aa2Sdanielk1977         eOpt==SQLITEASYNC_DELAY ? SQLITEASYNC_GET_DELAY :
2146f050aa2Sdanielk1977         SQLITEASYNC_GET_LOCKFILES, &iVal);
2156f050aa2Sdanielk1977   }
2166f050aa2Sdanielk1977 
2176f050aa2Sdanielk1977   if( rc!=SQLITE_OK ){
218e84d8d32Smistachkin     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
2196f050aa2Sdanielk1977     return TCL_ERROR;
2206f050aa2Sdanielk1977   }
2216f050aa2Sdanielk1977 
2226f050aa2Sdanielk1977   if( eOpt==SQLITEASYNC_HALT ){
2236f050aa2Sdanielk1977     Tcl_SetObjResult(interp, Tcl_NewStringObj(az[iVal], -1));
2246f050aa2Sdanielk1977   }else{
2256f050aa2Sdanielk1977     Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
2266f050aa2Sdanielk1977   }
2276f050aa2Sdanielk1977 
2286f050aa2Sdanielk1977   return TCL_OK;
2296f050aa2Sdanielk1977 }
2306f050aa2Sdanielk1977 
231a3f06598Sdanielk1977 #endif  /* SQLITE_ENABLE_ASYNCIO */
2322366940dSdrh 
2332366940dSdrh /*
2342366940dSdrh ** This routine registers the custom TCL commands defined in this
2352366940dSdrh ** module.  This should be the only procedure visible from outside
2362366940dSdrh ** of this module.
2372366940dSdrh */
Sqlitetestasync_Init(Tcl_Interp * interp)2382366940dSdrh int Sqlitetestasync_Init(Tcl_Interp *interp){
2393a0f13ffSdrh #ifdef SQLITE_ENABLE_ASYNCIO
2402366940dSdrh   Tcl_CreateObjCommand(interp,"sqlite3async_start",testAsyncStart,0,0);
2412366940dSdrh   Tcl_CreateObjCommand(interp,"sqlite3async_wait",testAsyncWait,0,0);
2426f050aa2Sdanielk1977 
2436f050aa2Sdanielk1977   Tcl_CreateObjCommand(interp,"sqlite3async_control",testAsyncControl,0,0);
2446f050aa2Sdanielk1977   Tcl_CreateObjCommand(interp,"sqlite3async_initialize",testAsyncInit,0,0);
2456f050aa2Sdanielk1977   Tcl_CreateObjCommand(interp,"sqlite3async_shutdown",testAsyncShutdown,0,0);
246a3f06598Sdanielk1977 #endif  /* SQLITE_ENABLE_ASYNCIO */
2472366940dSdrh   return TCL_OK;
2482366940dSdrh }
249