| Index: third_party/sqlite/src/src/test_async.c
|
| diff --git a/third_party/sqlite/src/src/test_async.c b/third_party/sqlite/src/src/test_async.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c760eea1fa2d6ddbec32497a673ec074c3963f90
|
| --- /dev/null
|
| +++ b/third_party/sqlite/src/src/test_async.c
|
| @@ -0,0 +1,241 @@
|
| +/*
|
| +** 2005 December 14
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +*************************************************************************
|
| +**
|
| +** This file contains a binding of the asynchronous IO extension interface
|
| +** (defined in ext/async/sqlite3async.h) to Tcl.
|
| +*/
|
| +
|
| +#define TCL_THREADS
|
| +#include <tcl.h>
|
| +
|
| +#ifdef SQLITE_ENABLE_ASYNCIO
|
| +
|
| +#include "sqlite3async.h"
|
| +#include "sqlite3.h"
|
| +#include <assert.h>
|
| +
|
| +/* From test1.c */
|
| +const char *sqlite3TestErrorName(int);
|
| +
|
| +
|
| +struct TestAsyncGlobal {
|
| + int isInstalled; /* True when async VFS is installed */
|
| +} testasync_g = { 0 };
|
| +
|
| +TCL_DECLARE_MUTEX(testasync_g_writerMutex);
|
| +
|
| +/*
|
| +** sqlite3async_initialize PARENT-VFS ISDEFAULT
|
| +*/
|
| +static int testAsyncInit(
|
| + void * clientData,
|
| + Tcl_Interp *interp,
|
| + int objc,
|
| + Tcl_Obj *CONST objv[]
|
| +){
|
| + const char *zParent;
|
| + int isDefault;
|
| + int rc;
|
| +
|
| + if( objc!=3 ){
|
| + Tcl_WrongNumArgs(interp, 1, objv, "PARENT-VFS ISDEFAULT");
|
| + return TCL_ERROR;
|
| + }
|
| + zParent = Tcl_GetString(objv[1]);
|
| + if( !*zParent ) {
|
| + zParent = 0;
|
| + }
|
| + if( Tcl_GetBooleanFromObj(interp, objv[2], &isDefault) ){
|
| + return TCL_ERROR;
|
| + }
|
| +
|
| + rc = sqlite3async_initialize(zParent, isDefault);
|
| + if( rc!=SQLITE_OK ){
|
| + Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3TestErrorName(rc), -1));
|
| + return TCL_ERROR;
|
| + }
|
| + return TCL_OK;
|
| +}
|
| +
|
| +/*
|
| +** sqlite3async_shutdown
|
| +*/
|
| +static int testAsyncShutdown(
|
| + void * clientData,
|
| + Tcl_Interp *interp,
|
| + int objc,
|
| + Tcl_Obj *CONST objv[]
|
| +){
|
| + sqlite3async_shutdown();
|
| + return TCL_OK;
|
| +}
|
| +
|
| +static Tcl_ThreadCreateType tclWriterThread(ClientData pIsStarted){
|
| + Tcl_MutexLock(&testasync_g_writerMutex);
|
| + *((int *)pIsStarted) = 1;
|
| + sqlite3async_run();
|
| + Tcl_MutexUnlock(&testasync_g_writerMutex);
|
| + Tcl_ExitThread(0);
|
| + TCL_THREAD_CREATE_RETURN;
|
| +}
|
| +
|
| +/*
|
| +** sqlite3async_start
|
| +**
|
| +** Start a new writer thread.
|
| +*/
|
| +static int testAsyncStart(
|
| + void * clientData,
|
| + Tcl_Interp *interp,
|
| + int objc,
|
| + Tcl_Obj *CONST objv[]
|
| +){
|
| + volatile int isStarted = 0;
|
| + ClientData threadData = (ClientData)&isStarted;
|
| +
|
| + Tcl_ThreadId x;
|
| + const int nStack = TCL_THREAD_STACK_DEFAULT;
|
| + const int flags = TCL_THREAD_NOFLAGS;
|
| + int rc;
|
| +
|
| + rc = Tcl_CreateThread(&x, tclWriterThread, threadData, nStack, flags);
|
| + if( rc!=TCL_OK ){
|
| + Tcl_AppendResult(interp, "Tcl_CreateThread() failed", 0);
|
| + return TCL_ERROR;
|
| + }
|
| +
|
| + while( isStarted==0 ) { /* Busy loop */ }
|
| + return TCL_OK;
|
| +}
|
| +
|
| +/*
|
| +** sqlite3async_wait
|
| +**
|
| +** Wait for the current writer thread to terminate.
|
| +**
|
| +** If the current writer thread is set to run forever then this
|
| +** command would block forever. To prevent that, an error is returned.
|
| +*/
|
| +static int testAsyncWait(
|
| + void * clientData,
|
| + Tcl_Interp *interp,
|
| + int objc,
|
| + Tcl_Obj *CONST objv[]
|
| +){
|
| + int eCond;
|
| + if( objc!=1 ){
|
| + Tcl_WrongNumArgs(interp, 1, objv, "");
|
| + return TCL_ERROR;
|
| + }
|
| +
|
| + sqlite3async_control(SQLITEASYNC_GET_HALT, &eCond);
|
| + if( eCond==SQLITEASYNC_HALT_NEVER ){
|
| + Tcl_AppendResult(interp, "would block forever", (char*)0);
|
| + return TCL_ERROR;
|
| + }
|
| +
|
| + Tcl_MutexLock(&testasync_g_writerMutex);
|
| + Tcl_MutexUnlock(&testasync_g_writerMutex);
|
| + return TCL_OK;
|
| +}
|
| +
|
| +/*
|
| +** sqlite3async_control OPTION ?VALUE?
|
| +*/
|
| +static int testAsyncControl(
|
| + void * clientData,
|
| + Tcl_Interp *interp,
|
| + int objc,
|
| + Tcl_Obj *CONST objv[]
|
| +){
|
| + int rc = SQLITE_OK;
|
| + int aeOpt[] = { SQLITEASYNC_HALT, SQLITEASYNC_DELAY, SQLITEASYNC_LOCKFILES };
|
| + const char *azOpt[] = { "halt", "delay", "lockfiles", 0 };
|
| + const char *az[] = { "never", "now", "idle", 0 };
|
| + int iVal;
|
| + int eOpt;
|
| +
|
| + if( objc!=2 && objc!=3 ){
|
| + Tcl_WrongNumArgs(interp, 1, objv, "OPTION ?VALUE?");
|
| + return TCL_ERROR;
|
| + }
|
| + if( Tcl_GetIndexFromObj(interp, objv[1], azOpt, "option", 0, &eOpt) ){
|
| + return TCL_ERROR;
|
| + }
|
| + eOpt = aeOpt[eOpt];
|
| +
|
| + if( objc==3 ){
|
| + switch( eOpt ){
|
| + case SQLITEASYNC_HALT: {
|
| + assert( SQLITEASYNC_HALT_NEVER==0 );
|
| + assert( SQLITEASYNC_HALT_NOW==1 );
|
| + assert( SQLITEASYNC_HALT_IDLE==2 );
|
| + if( Tcl_GetIndexFromObj(interp, objv[2], az, "value", 0, &iVal) ){
|
| + return TCL_ERROR;
|
| + }
|
| + break;
|
| + }
|
| + case SQLITEASYNC_DELAY:
|
| + if( Tcl_GetIntFromObj(interp, objv[2], &iVal) ){
|
| + return TCL_ERROR;
|
| + }
|
| + break;
|
| +
|
| + case SQLITEASYNC_LOCKFILES:
|
| + if( Tcl_GetBooleanFromObj(interp, objv[2], &iVal) ){
|
| + return TCL_ERROR;
|
| + }
|
| + break;
|
| + }
|
| +
|
| + rc = sqlite3async_control(eOpt, iVal);
|
| + }
|
| +
|
| + if( rc==SQLITE_OK ){
|
| + rc = sqlite3async_control(
|
| + eOpt==SQLITEASYNC_HALT ? SQLITEASYNC_GET_HALT :
|
| + eOpt==SQLITEASYNC_DELAY ? SQLITEASYNC_GET_DELAY :
|
| + SQLITEASYNC_GET_LOCKFILES, &iVal);
|
| + }
|
| +
|
| + if( rc!=SQLITE_OK ){
|
| + Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3TestErrorName(rc), -1));
|
| + return TCL_ERROR;
|
| + }
|
| +
|
| + if( eOpt==SQLITEASYNC_HALT ){
|
| + Tcl_SetObjResult(interp, Tcl_NewStringObj(az[iVal], -1));
|
| + }else{
|
| + Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
|
| + }
|
| +
|
| + return TCL_OK;
|
| +}
|
| +
|
| +#endif /* SQLITE_ENABLE_ASYNCIO */
|
| +
|
| +/*
|
| +** This routine registers the custom TCL commands defined in this
|
| +** module. This should be the only procedure visible from outside
|
| +** of this module.
|
| +*/
|
| +int Sqlitetestasync_Init(Tcl_Interp *interp){
|
| +#ifdef SQLITE_ENABLE_ASYNCIO
|
| + Tcl_CreateObjCommand(interp,"sqlite3async_start",testAsyncStart,0,0);
|
| + Tcl_CreateObjCommand(interp,"sqlite3async_wait",testAsyncWait,0,0);
|
| +
|
| + Tcl_CreateObjCommand(interp,"sqlite3async_control",testAsyncControl,0,0);
|
| + Tcl_CreateObjCommand(interp,"sqlite3async_initialize",testAsyncInit,0,0);
|
| + Tcl_CreateObjCommand(interp,"sqlite3async_shutdown",testAsyncShutdown,0,0);
|
| +#endif /* SQLITE_ENABLE_ASYNCIO */
|
| + return TCL_OK;
|
| +}
|
|
|