test_async.c 5.7 KB

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