Snapshot of upstream SQLite 3.45.3
[sqlcipher.git] / src / test_async.c
blobc32c74c6608142d36e6a7d323b56877983eff301
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.
11 *************************************************************************
13 ** This file contains a binding of the asynchronous IO extension interface
14 ** (defined in ext/async/sqlite3async.h) to Tcl.
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
27 #ifdef SQLITE_ENABLE_ASYNCIO
29 #include "sqlite3async.h"
30 #include "sqlite3.h"
31 #include <assert.h>
33 /* From main.c */
34 extern const char *sqlite3ErrName(int);
37 struct TestAsyncGlobal {
38 int isInstalled; /* True when async VFS is installed */
39 } testasync_g = { 0 };
41 TCL_DECLARE_MUTEX(testasync_g_writerMutex);
44 ** sqlite3async_initialize PARENT-VFS ISDEFAULT
46 static int SQLITE_TCLAPI testAsyncInit(
47 void * clientData,
48 Tcl_Interp *interp,
49 int objc,
50 Tcl_Obj *CONST objv[]
52 const char *zParent;
53 int isDefault;
54 int rc;
56 if( objc!=3 ){
57 Tcl_WrongNumArgs(interp, 1, objv, "PARENT-VFS ISDEFAULT");
58 return TCL_ERROR;
60 zParent = Tcl_GetString(objv[1]);
61 if( !*zParent ) {
62 zParent = 0;
64 if( Tcl_GetBooleanFromObj(interp, objv[2], &isDefault) ){
65 return TCL_ERROR;
68 rc = sqlite3async_initialize(zParent, isDefault);
69 if( rc!=SQLITE_OK ){
70 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
71 return TCL_ERROR;
73 return TCL_OK;
77 ** sqlite3async_shutdown
79 static int SQLITE_TCLAPI testAsyncShutdown(
80 void * clientData,
81 Tcl_Interp *interp,
82 int objc,
83 Tcl_Obj *CONST objv[]
85 sqlite3async_shutdown();
86 return TCL_OK;
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;
99 ** sqlite3async_start
101 ** Start a new writer thread.
103 static int SQLITE_TCLAPI testAsyncStart(
104 void * clientData,
105 Tcl_Interp *interp,
106 int objc,
107 Tcl_Obj *CONST objv[]
109 volatile int isStarted = 0;
110 ClientData threadData = (ClientData)&isStarted;
112 Tcl_ThreadId x;
113 const int nStack = TCL_THREAD_STACK_DEFAULT;
114 const int flags = TCL_THREAD_NOFLAGS;
115 int rc;
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;
123 while( isStarted==0 ) { /* Busy loop */ }
124 return TCL_OK;
128 ** sqlite3async_wait
130 ** Wait for the current writer thread to terminate.
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.
135 static int SQLITE_TCLAPI testAsyncWait(
136 void * clientData,
137 Tcl_Interp *interp,
138 int objc,
139 Tcl_Obj *CONST objv[]
141 int eCond;
142 if( objc!=1 ){
143 Tcl_WrongNumArgs(interp, 1, objv, "");
144 return TCL_ERROR;
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;
153 Tcl_MutexLock(&testasync_g_writerMutex);
154 Tcl_MutexUnlock(&testasync_g_writerMutex);
155 return TCL_OK;
159 ** sqlite3async_control OPTION ?VALUE?
161 static int SQLITE_TCLAPI testAsyncControl(
162 void * clientData,
163 Tcl_Interp *interp,
164 int objc,
165 Tcl_Obj *CONST objv[]
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;
174 if( objc!=2 && objc!=3 ){
175 Tcl_WrongNumArgs(interp, 1, objv, "OPTION ?VALUE?");
176 return TCL_ERROR;
178 if( Tcl_GetIndexFromObj(interp, objv[1], azOpt, "option", 0, &eOpt) ){
179 return TCL_ERROR;
181 eOpt = aeOpt[eOpt];
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;
192 break;
194 case SQLITEASYNC_DELAY:
195 if( Tcl_GetIntFromObj(interp, objv[2], &iVal) ){
196 return TCL_ERROR;
198 break;
200 case SQLITEASYNC_LOCKFILES:
201 if( Tcl_GetBooleanFromObj(interp, objv[2], &iVal) ){
202 return TCL_ERROR;
204 break;
207 rc = sqlite3async_control(eOpt, iVal);
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);
217 if( rc!=SQLITE_OK ){
218 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
219 return TCL_ERROR;
222 if( eOpt==SQLITEASYNC_HALT ){
223 Tcl_SetObjResult(interp, Tcl_NewStringObj(az[iVal], -1));
224 }else{
225 Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
228 return TCL_OK;
231 #endif /* SQLITE_ENABLE_ASYNCIO */
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.
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);
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;