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