OLD | NEW |
1 /* | 1 /* |
2 ** 2006 January 09 | 2 ** 2006 January 09 |
3 ** | 3 ** |
4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
6 ** | 6 ** |
7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
10 ** | 10 ** |
(...skipping 22 matching lines...) Expand all Loading... |
33 */ | 33 */ |
34 int sqlite3_client_open(const char*, sqlite3**); | 34 int sqlite3_client_open(const char*, sqlite3**); |
35 int sqlite3_client_prepare(sqlite3*,const char*,int, | 35 int sqlite3_client_prepare(sqlite3*,const char*,int, |
36 sqlite3_stmt**,const char**); | 36 sqlite3_stmt**,const char**); |
37 int sqlite3_client_step(sqlite3_stmt*); | 37 int sqlite3_client_step(sqlite3_stmt*); |
38 int sqlite3_client_reset(sqlite3_stmt*); | 38 int sqlite3_client_reset(sqlite3_stmt*); |
39 int sqlite3_client_finalize(sqlite3_stmt*); | 39 int sqlite3_client_finalize(sqlite3_stmt*); |
40 int sqlite3_client_close(sqlite3*); | 40 int sqlite3_client_close(sqlite3*); |
41 int sqlite3_server_start(void); | 41 int sqlite3_server_start(void); |
42 int sqlite3_server_stop(void); | 42 int sqlite3_server_stop(void); |
| 43 void sqlite3_server_start2(int *pnDecr); |
43 | 44 |
44 /* | 45 /* |
45 ** Each thread is controlled by an instance of the following | 46 ** Each thread is controlled by an instance of the following |
46 ** structure. | 47 ** structure. |
47 */ | 48 */ |
48 typedef struct Thread Thread; | 49 typedef struct Thread Thread; |
49 struct Thread { | 50 struct Thread { |
50 /* The first group of fields are writable by the supervisor thread | 51 /* The first group of fields are writable by the supervisor thread |
51 ** and read-only to the client threads | 52 ** and read-only to the client threads |
52 */ | 53 */ |
53 char *zFilename; /* Name of database file */ | 54 char *zFilename; /* Name of database file */ |
54 void (*xOp)(Thread*); /* next operation to do */ | 55 void (*xOp)(Thread*); /* next operation to do */ |
55 char *zArg; /* argument usable by xOp */ | 56 char *zArg; /* argument usable by xOp */ |
56 volatile int opnum; /* Operation number */ | 57 volatile int opnum; /* Operation number */ |
57 volatile int busy; /* True if this thread is in use */ | 58 volatile int busy; /* True if this thread is in use */ |
58 | 59 |
59 /* The next group of fields are writable by the client threads | 60 /* The next group of fields are writable by the client threads |
60 ** but read-only to the superviser thread. | 61 ** but read-only to the superviser thread. |
61 */ | 62 */ |
62 volatile int completed; /* Number of operations completed */ | 63 volatile int completed; /* Number of operations completed */ |
63 sqlite3 *db; /* Open database */ | 64 sqlite3 *db; /* Open database */ |
64 sqlite3_stmt *pStmt; /* Pending operation */ | 65 sqlite3_stmt *pStmt; /* Pending operation */ |
65 char *zErr; /* operation error */ | 66 char *zErr; /* operation error */ |
66 char *zStaticErr; /* Static error message */ | 67 char *zStaticErr; /* Static error message */ |
67 int rc; /* operation return code */ | 68 int rc; /* operation return code */ |
68 int argc; /* number of columns in result */ | 69 int argc; /* number of columns in result */ |
69 const char *argv[100]; /* result columns */ | 70 const char *argv[100]; /* result columns */ |
70 const char *colv[100]; /* result column names */ | 71 const char *colv[100]; /* result column names */ |
| 72 |
| 73 /* Initialized to 1 by the supervisor thread when the client is |
| 74 ** created, and then deemed read-only to the supervisor thread. |
| 75 ** Is set to 0 by the server thread belonging to this client |
| 76 ** just before it exits. |
| 77 */ |
| 78 int nServer; /* Number of server threads running */ |
71 }; | 79 }; |
72 | 80 |
73 /* | 81 /* |
74 ** There can be as many as 26 threads running at once. Each is named | 82 ** There can be as many as 26 threads running at once. Each is named |
75 ** by a capital letter: A, B, C, ..., Y, Z. | 83 ** by a capital letter: A, B, C, ..., Y, Z. |
76 */ | 84 */ |
77 #define N_THREAD 26 | 85 #define N_THREAD 26 |
78 static Thread threadset[N_THREAD]; | 86 static Thread threadset[N_THREAD]; |
79 | 87 |
80 /* | 88 /* |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 threadset[i].opnum = 1; | 176 threadset[i].opnum = 1; |
169 threadset[i].completed = 0; | 177 threadset[i].completed = 0; |
170 rc = pthread_create(&x, 0, client_main, &threadset[i]); | 178 rc = pthread_create(&x, 0, client_main, &threadset[i]); |
171 if( rc ){ | 179 if( rc ){ |
172 Tcl_AppendResult(interp, "failed to create the thread", 0); | 180 Tcl_AppendResult(interp, "failed to create the thread", 0); |
173 sqlite3_free(threadset[i].zFilename); | 181 sqlite3_free(threadset[i].zFilename); |
174 threadset[i].busy = 0; | 182 threadset[i].busy = 0; |
175 return TCL_ERROR; | 183 return TCL_ERROR; |
176 } | 184 } |
177 pthread_detach(x); | 185 pthread_detach(x); |
178 sqlite3_server_start(); | 186 if( threadset[i].nServer==0 ){ |
| 187 threadset[i].nServer = 1; |
| 188 sqlite3_server_start2(&threadset[i].nServer); |
| 189 } |
179 return TCL_OK; | 190 return TCL_OK; |
180 } | 191 } |
181 | 192 |
182 /* | 193 /* |
183 ** Wait for a thread to reach its idle state. | 194 ** Wait for a thread to reach its idle state. |
184 */ | 195 */ |
185 static void client_wait(Thread *p){ | 196 static void client_wait(Thread *p){ |
186 while( p->opnum>p->completed ) sched_yield(); | 197 while( p->opnum>p->completed ) sched_yield(); |
187 } | 198 } |
188 | 199 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 Tcl_AppendResult(interp, "no such thread", 0); | 272 Tcl_AppendResult(interp, "no such thread", 0); |
262 return TCL_ERROR; | 273 return TCL_ERROR; |
263 } | 274 } |
264 stop_thread(&threadset[i]); | 275 stop_thread(&threadset[i]); |
265 } | 276 } |
266 | 277 |
267 /* If no client threads are still running, also stop the server */ | 278 /* If no client threads are still running, also stop the server */ |
268 for(i=0; i<N_THREAD && threadset[i].busy==0; i++){} | 279 for(i=0; i<N_THREAD && threadset[i].busy==0; i++){} |
269 if( i>=N_THREAD ){ | 280 if( i>=N_THREAD ){ |
270 sqlite3_server_stop(); | 281 sqlite3_server_stop(); |
| 282 while( 1 ){ |
| 283 for(i=0; i<N_THREAD && threadset[i].nServer==0; i++); |
| 284 if( i==N_THREAD ) break; |
| 285 sched_yield(); |
| 286 } |
271 } | 287 } |
272 return TCL_OK; | 288 return TCL_OK; |
273 } | 289 } |
274 | 290 |
275 /* | 291 /* |
276 ** Usage: client_argc ID | 292 ** Usage: client_argc ID |
277 ** | 293 ** |
278 ** Wait on the most recent client_step to complete, then return the | 294 ** Wait on the most recent client_step to complete, then return the |
279 ** number of columns in the result set. | 295 ** number of columns in the result set. |
280 */ | 296 */ |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; | 385 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; |
370 client_wait(&threadset[i]); | 386 client_wait(&threadset[i]); |
371 if( n<0 || n>=threadset[i].argc ){ | 387 if( n<0 || n>=threadset[i].argc ){ |
372 Tcl_AppendResult(interp, "column number out of range", 0); | 388 Tcl_AppendResult(interp, "column number out of range", 0); |
373 return TCL_ERROR; | 389 return TCL_ERROR; |
374 } | 390 } |
375 Tcl_AppendResult(interp, threadset[i].colv[n], 0); | 391 Tcl_AppendResult(interp, threadset[i].colv[n], 0); |
376 return TCL_OK; | 392 return TCL_OK; |
377 } | 393 } |
378 | 394 |
| 395 extern const char *sqlite3ErrName(int); |
| 396 |
379 /* | 397 /* |
380 ** Usage: client_result ID | 398 ** Usage: client_result ID |
381 ** | 399 ** |
382 ** Wait on the most recent operation to complete, then return the | 400 ** Wait on the most recent operation to complete, then return the |
383 ** result code from that operation. | 401 ** result code from that operation. |
384 */ | 402 */ |
385 static int tcl_client_result( | 403 static int tcl_client_result( |
386 void *NotUsed, | 404 void *NotUsed, |
387 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | 405 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
388 int argc, /* Number of arguments */ | 406 int argc, /* Number of arguments */ |
389 const char **argv /* Text of each argument */ | 407 const char **argv /* Text of each argument */ |
390 ){ | 408 ){ |
391 int i; | 409 int i; |
392 const char *zName; | 410 const char *zName; |
393 | 411 |
394 if( argc!=2 ){ | 412 if( argc!=2 ){ |
395 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | 413 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
396 " ID", 0); | 414 " ID", 0); |
397 return TCL_ERROR; | 415 return TCL_ERROR; |
398 } | 416 } |
399 i = parse_client_id(interp, argv[1]); | 417 i = parse_client_id(interp, argv[1]); |
400 if( i<0 ) return TCL_ERROR; | 418 if( i<0 ) return TCL_ERROR; |
401 if( !threadset[i].busy ){ | 419 if( !threadset[i].busy ){ |
402 Tcl_AppendResult(interp, "no such thread", 0); | 420 Tcl_AppendResult(interp, "no such thread", 0); |
403 return TCL_ERROR; | 421 return TCL_ERROR; |
404 } | 422 } |
405 client_wait(&threadset[i]); | 423 client_wait(&threadset[i]); |
406 switch( threadset[i].rc ){ | 424 zName = sqlite3ErrName(threadset[i].rc); |
407 case SQLITE_OK: zName = "SQLITE_OK"; break; | |
408 case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; | |
409 case SQLITE_PERM: zName = "SQLITE_PERM"; break; | |
410 case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; | |
411 case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; | |
412 case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; | |
413 case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; | |
414 case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; | |
415 case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; | |
416 case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; | |
417 case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; | |
418 case SQLITE_FULL: zName = "SQLITE_FULL"; break; | |
419 case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; | |
420 case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; | |
421 case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; | |
422 case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; | |
423 case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; | |
424 case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; | |
425 case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; | |
426 case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; | |
427 case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; | |
428 case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; | |
429 case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; | |
430 case SQLITE_ROW: zName = "SQLITE_ROW"; break; | |
431 case SQLITE_DONE: zName = "SQLITE_DONE"; break; | |
432 default: zName = "SQLITE_Unknown"; break; | |
433 } | |
434 Tcl_AppendResult(interp, zName, 0); | 425 Tcl_AppendResult(interp, zName, 0); |
435 return TCL_OK; | 426 return TCL_OK; |
436 } | 427 } |
437 | 428 |
438 /* | 429 /* |
439 ** Usage: client_error ID | 430 ** Usage: client_error ID |
440 ** | 431 ** |
441 ** Wait on the most recent operation to complete, then return the | 432 ** Wait on the most recent operation to complete, then return the |
442 ** error string. | 433 ** error string. |
443 */ | 434 */ |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
714 int i; | 705 int i; |
715 | 706 |
716 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ | 707 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ |
717 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); | 708 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); |
718 } | 709 } |
719 return TCL_OK; | 710 return TCL_OK; |
720 } | 711 } |
721 #else | 712 #else |
722 int Sqlitetest7_Init(Tcl_Interp *interp){ return TCL_OK; } | 713 int Sqlitetest7_Init(Tcl_Interp *interp){ return TCL_OK; } |
723 #endif /* SQLITE_OS_UNIX */ | 714 #endif /* SQLITE_OS_UNIX */ |
OLD | NEW |