xref: /sqlite-3.40.0/src/test_async.c (revision 999cc5d7)
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 an example implementation of an asynchronous IO
14 ** backend for SQLite.
15 **
16 ** WHAT IS ASYNCHRONOUS I/O?
17 **
18 ** With asynchronous I/O, write requests are handled by a separate thread
19 ** running in the background.  This means that the thread that initiates
20 ** a database write does not have to wait for (sometimes slow) disk I/O
21 ** to occur.  The write seems to happen very quickly, though in reality
22 ** it is happening at its usual slow pace in the background.
23 **
24 ** Asynchronous I/O appears to give better responsiveness, but at a price.
25 ** You lose the Durable property.  With the default I/O backend of SQLite,
26 ** once a write completes, you know that the information you wrote is
27 ** safely on disk.  With the asynchronous I/O, this is no the case.  If
28 ** your program crashes or if you take a power lose after the database
29 ** write but before the asynchronous write thread has completed, then the
30 ** database change might never make it to disk and the next user of the
31 ** database might not see your change.
32 **
33 ** You lose Durability with asynchronous I/O, but you still retain the
34 ** other parts of ACID:  Atomic,  Consistent, and Isolated.  Many
35 ** appliations get along fine without the Durablity.
36 **
37 ** HOW IT WORKS
38 **
39 ** Asynchronous I/O works by overloading the OS-layer disk I/O routines
40 ** with modified versions that store the data to be written in queue of
41 ** pending write operations.  Look at the asyncEnable() subroutine to see
42 ** how overloading works.  Six os-layer routines are overloaded:
43 **
44 **     sqlite3OsOpenReadWrite;
45 **     sqlite3OsOpenReadOnly;
46 **     sqlite3OsOpenExclusive;
47 **     sqlite3OsDelete;
48 **     sqlite3OsFileExists;
49 **     sqlite3OsSyncDirectory;
50 **
51 ** The original implementations of these routines are saved and are
52 ** used by the writer thread to do the real I/O.  The substitute
53 ** implementations typically put the I/O operation on a queue
54 ** to be handled later by the writer thread, though read operations
55 ** must be handled right away, obviously.
56 **
57 ** Asynchronous I/O is disabled by setting the os-layer interface routines
58 ** back to their original values.
59 **
60 ** LIMITATIONS
61 **
62 ** This demonstration code is deliberately kept simple in order to keep
63 ** the main ideas clear and easy to understand.  Real applications that
64 ** want to do asynchronous I/O might want to add additional capabilities.
65 ** For example, in this demonstration if writes are happening at a steady
66 ** stream that exceeds the I/O capability of the background writer thread,
67 ** the queue of pending write operations will grow without bound until we
68 ** run out of memory.  Users of this technique may want to keep track of
69 ** the quantity of pending writes and stop accepting new write requests
70 ** when the buffer gets to be too big.
71 */
72 
73 #include "sqliteInt.h"
74 #include <tcl.h>
75 
76 /*
77 ** This test uses pthreads and hence only works on unix and with
78 ** a threadsafe build of SQLite.
79 */
80 #if OS_UNIX && SQLITE_THREADSAFE
81 
82 /*
83 ** This demo uses pthreads.  If you do not have a pthreads implementation
84 ** for your operating system, you will need to recode the threading
85 ** logic.
86 */
87 #include <pthread.h>
88 #include <sched.h>
89 
90 /* Useful macros used in several places */
91 #define MIN(x,y) ((x)<(y)?(x):(y))
92 #define MAX(x,y) ((x)>(y)?(x):(y))
93 
94 /* Forward references */
95 typedef struct AsyncWrite AsyncWrite;
96 typedef struct AsyncFile AsyncFile;
97 typedef struct AsyncFileData AsyncFileData;
98 
99 /* Enable for debugging */
100 static int sqlite3async_trace = 0;
101 # define ASYNC_TRACE(X) if( sqlite3async_trace ) asyncTrace X
102 static void asyncTrace(const char *zFormat, ...){
103   char *z;
104   va_list ap;
105   va_start(ap, zFormat);
106   z = sqlite3_vmprintf(zFormat, ap);
107   va_end(ap);
108   fprintf(stderr, "[%d] %s", (int)pthread_self(), z);
109   sqlite3_free(z);
110 }
111 
112 /*
113 ** THREAD SAFETY NOTES
114 **
115 ** Basic rules:
116 **
117 **     * Both read and write access to the global write-op queue must be
118 **       protected by the async.queueMutex.
119 **
120 **     * The file handles from the underlying system are assumed not to
121 **       be thread safe.
122 **
123 **     * See the last two paragraphs under "The Writer Thread" for
124 **       an assumption to do with file-handle synchronization by the Os.
125 **
126 ** File system operations (invoked by SQLite thread):
127 **
128 **     xOpenXXX (three versions)
129 **     xDelete
130 **     xFileExists
131 **     xSyncDirectory
132 **
133 ** File handle operations (invoked by SQLite thread):
134 **
135 **         asyncWrite, asyncClose, asyncTruncate, asyncSync,
136 **         asyncSetFullSync, asyncOpenDirectory.
137 **
138 **     The operations above add an entry to the global write-op list. They
139 **     prepare the entry, acquire the async.queueMutex momentarily while
140 **     list pointers are  manipulated to insert the new entry, then release
141 **     the mutex and signal the writer thread to wake up in case it happens
142 **     to be asleep.
143 **
144 **
145 **         asyncRead, asyncFileSize.
146 **
147 **     Read operations. Both of these read from both the underlying file
148 **     first then adjust their result based on pending writes in the
149 **     write-op queue.   So async.queueMutex is held for the duration
150 **     of these operations to prevent other threads from changing the
151 **     queue in mid operation.
152 **
153 **
154 **         asyncLock, asyncUnlock, asyncLockState, asyncCheckReservedLock
155 **
156 **     These primitives implement in-process locking using a hash table
157 **     on the file name.  Files are locked correctly for connections coming
158 **     from the same process.  But other processes cannot see these locks
159 **     and will therefore not honor them.
160 **
161 **
162 **         asyncFileHandle.
163 **
164 **     The sqlite3OsFileHandle() function is currently only used when
165 **     debugging the pager module. Unless sqlite3OsClose() is called on the
166 **     file (shouldn't be possible for other reasons), the underlying
167 **     implementations are safe to call without grabbing any mutex. So we just
168 **     go ahead and call it no matter what any other threads are doing.
169 **
170 **
171 **         asyncSeek.
172 **
173 **     Calling this method just manipulates the AsyncFile.iOffset variable.
174 **     Since this variable is never accessed by writer thread, this
175 **     function does not require the mutex.  Actual calls to OsSeek() take
176 **     place just before OsWrite() or OsRead(), which are always protected by
177 **     the mutex.
178 **
179 ** The writer thread:
180 **
181 **     The async.writerMutex is used to make sure only there is only
182 **     a single writer thread running at a time.
183 **
184 **     Inside the writer thread is a loop that works like this:
185 **
186 **         WHILE (write-op list is not empty)
187 **             Do IO operation at head of write-op list
188 **             Remove entry from head of write-op list
189 **         END WHILE
190 **
191 **     The async.queueMutex is always held during the <write-op list is
192 **     not empty> test, and when the entry is removed from the head
193 **     of the write-op list. Sometimes it is held for the interim
194 **     period (while the IO is performed), and sometimes it is
195 **     relinquished. It is relinquished if (a) the IO op is an
196 **     ASYNC_CLOSE or (b) when the file handle was opened, two of
197 **     the underlying systems handles were opened on the same
198 **     file-system entry.
199 **
200 **     If condition (b) above is true, then one file-handle
201 **     (AsyncFile.pBaseRead) is used exclusively by sqlite threads to read the
202 **     file, the other (AsyncFile.pBaseWrite) by sqlite3_async_flush()
203 **     threads to perform write() operations. This means that read
204 **     operations are not blocked by asynchronous writes (although
205 **     asynchronous writes may still be blocked by reads).
206 **
207 **     This assumes that the OS keeps two handles open on the same file
208 **     properly in sync. That is, any read operation that starts after a
209 **     write operation on the same file system entry has completed returns
210 **     data consistent with the write. We also assume that if one thread
211 **     reads a file while another is writing it all bytes other than the
212 **     ones actually being written contain valid data.
213 **
214 **     If the above assumptions are not true, set the preprocessor symbol
215 **     SQLITE_ASYNC_TWO_FILEHANDLES to 0.
216 */
217 
218 #ifndef SQLITE_ASYNC_TWO_FILEHANDLES
219 /* #define SQLITE_ASYNC_TWO_FILEHANDLES 0 */
220 #define SQLITE_ASYNC_TWO_FILEHANDLES 1
221 #endif
222 
223 /*
224 ** State information is held in the static variable "async" defined
225 ** as follows:
226 */
227 static struct TestAsyncStaticData {
228   pthread_mutex_t queueMutex;  /* Mutex for access to write operation queue */
229   pthread_mutex_t writerMutex; /* Prevents multiple writer threads */
230   pthread_mutex_t lockMutex;   /* For access to aLock hash table */
231   pthread_cond_t queueSignal;  /* For waking up sleeping writer thread */
232   pthread_cond_t emptySignal;  /* Notify when the write queue is empty */
233   AsyncWrite *pQueueFirst;     /* Next write operation to be processed */
234   AsyncWrite *pQueueLast;      /* Last write operation on the list */
235   Hash aLock;                  /* Files locked */
236   volatile int ioDelay;             /* Extra delay between write operations */
237   volatile int writerHaltWhenIdle;  /* Writer thread halts when queue empty */
238   volatile int writerHaltNow;       /* Writer thread halts after next op */
239   int ioError;                 /* True if an IO error has occured */
240   int nFile;                   /* Number of open files (from sqlite pov) */
241 } async = {
242   PTHREAD_MUTEX_INITIALIZER,
243   PTHREAD_MUTEX_INITIALIZER,
244   PTHREAD_MUTEX_INITIALIZER,
245   PTHREAD_COND_INITIALIZER,
246   PTHREAD_COND_INITIALIZER,
247 };
248 
249 /* Possible values of AsyncWrite.op */
250 #define ASYNC_NOOP          0
251 #define ASYNC_WRITE         1
252 #define ASYNC_SYNC          2
253 #define ASYNC_TRUNCATE      3
254 #define ASYNC_CLOSE         4
255 #define ASYNC_OPENDIRECTORY 5
256 #define ASYNC_SETFULLSYNC   6
257 #define ASYNC_DELETE        7
258 #define ASYNC_OPENEXCLUSIVE 8
259 #define ASYNC_SYNCDIRECTORY 9
260 
261 /* Names of opcodes.  Used for debugging only.
262 ** Make sure these stay in sync with the macros above!
263 */
264 static const char *azOpcodeName[] = {
265   "NOOP", "WRITE", "SYNC", "TRUNCATE", "CLOSE",
266   "OPENDIR", "SETFULLSYNC", "DELETE", "OPENEX", "SYNCDIR",
267 };
268 
269 /*
270 ** Entries on the write-op queue are instances of the AsyncWrite
271 ** structure, defined here.
272 **
273 ** The interpretation of the iOffset and nByte variables varies depending
274 ** on the value of AsyncWrite.op:
275 **
276 ** ASYNC_WRITE:
277 **     iOffset -> Offset in file to write to.
278 **     nByte   -> Number of bytes of data to write (pointed to by zBuf).
279 **
280 ** ASYNC_SYNC:
281 **     nByte   -> flags to pass to sqlite3OsSync().
282 **
283 ** ASYNC_TRUNCATE:
284 **     iOffset -> Size to truncate file to.
285 **     nByte   -> Unused.
286 **
287 ** ASYNC_CLOSE:
288 **     iOffset -> Unused.
289 **     nByte   -> Unused.
290 **
291 ** ASYNC_OPENDIRECTORY:
292 **     iOffset -> Unused.
293 **     nByte   -> Number of bytes of zBuf points to (directory name).
294 **
295 ** ASYNC_SETFULLSYNC:
296 **     iOffset -> Unused.
297 **     nByte   -> New value for the full-sync flag.
298 **
299 **
300 ** ASYNC_DELETE:
301 **     iOffset -> Contains the "syncDir" flag.
302 **     nByte   -> Number of bytes of zBuf points to (file name).
303 **
304 ** ASYNC_OPENEXCLUSIVE:
305 **     iOffset -> Value of "delflag".
306 **     nByte   -> Number of bytes of zBuf points to (file name).
307 **
308 **
309 ** For an ASYNC_WRITE operation, zBuf points to the data to write to the file.
310 ** This space is sqlite3_malloc()d along with the AsyncWrite structure in a
311 ** single blob, so is deleted when sqlite3_free() is called on the parent
312 ** structure.
313 */
314 struct AsyncWrite {
315   AsyncFileData *pFileData;    /* File to write data to or sync */
316   int op;                      /* One of ASYNC_xxx etc. */
317   i64 iOffset;        /* See above */
318   int nByte;          /* See above */
319   char *zBuf;         /* Data to write to file (or NULL if op!=ASYNC_WRITE) */
320   AsyncWrite *pNext;  /* Next write operation (to any file) */
321 };
322 
323 /*
324 ** The AsyncFile structure is a subclass of sqlite3_file used for
325 ** asynchronous IO.
326 **
327 ** All of the actual data for the structure is stored in the structure
328 ** pointed to by AsyncFile.pData, which is allocated as part of the
329 ** sqlite3OsOpen() using sqlite3_malloc(). The reason for this is that the
330 ** lifetime of the AsyncFile structure is ended by the caller after OsClose()
331 ** is called, but the data in AsyncFileData may be required by the
332 ** writer thread after that point.
333 */
334 struct AsyncFile {
335   sqlite3_io_methods *pMethod;
336   AsyncFileData *pData;
337 };
338 struct AsyncFileData {
339   char *zName;               /* Underlying OS filename - used for debugging */
340   int nName;                 /* Number of characters in zName */
341   sqlite3_file *pBaseRead;   /* Read handle to the underlying Os file */
342   sqlite3_file *pBaseWrite;  /* Write handle to the underlying Os file */
343 };
344 
345 /*
346 ** Add an entry to the end of the global write-op list. pWrite should point
347 ** to an AsyncWrite structure allocated using sqlite3_malloc().  The writer
348 ** thread will call sqlite3_free() to free the structure after the specified
349 ** operation has been completed.
350 **
351 ** Once an AsyncWrite structure has been added to the list, it becomes the
352 ** property of the writer thread and must not be read or modified by the
353 ** caller.
354 */
355 static void addAsyncWrite(AsyncWrite *pWrite){
356   /* We must hold the queue mutex in order to modify the queue pointers */
357   pthread_mutex_lock(&async.queueMutex);
358 
359   /* Add the record to the end of the write-op queue */
360   assert( !pWrite->pNext );
361   if( async.pQueueLast ){
362     assert( async.pQueueFirst );
363     async.pQueueLast->pNext = pWrite;
364   }else{
365     async.pQueueFirst = pWrite;
366   }
367   async.pQueueLast = pWrite;
368   ASYNC_TRACE(("PUSH %p (%s %s %d)\n", pWrite, azOpcodeName[pWrite->op],
369          pWrite->pFileData ? pWrite->pFileData->zName : "-", pWrite->iOffset));
370 
371   if( pWrite->op==ASYNC_CLOSE ){
372     async.nFile--;
373     if( async.nFile==0 ){
374       async.ioError = SQLITE_OK;
375     }
376   }
377 
378   /* Drop the queue mutex */
379   pthread_mutex_unlock(&async.queueMutex);
380 
381   /* The writer thread might have been idle because there was nothing
382   ** on the write-op queue for it to do.  So wake it up. */
383   pthread_cond_signal(&async.queueSignal);
384 }
385 
386 /*
387 ** Increment async.nFile in a thread-safe manner.
388 */
389 static void incrOpenFileCount(){
390   /* We must hold the queue mutex in order to modify async.nFile */
391   pthread_mutex_lock(&async.queueMutex);
392   if( async.nFile==0 ){
393     async.ioError = SQLITE_OK;
394   }
395   async.nFile++;
396   pthread_mutex_unlock(&async.queueMutex);
397 }
398 
399 /*
400 ** This is a utility function to allocate and populate a new AsyncWrite
401 ** structure and insert it (via addAsyncWrite() ) into the global list.
402 */
403 static int addNewAsyncWrite(
404   AsyncFileData *pFileData,
405   int op,
406   i64 iOffset,
407   int nByte,
408   const char *zByte
409 ){
410   AsyncWrite *p;
411   if( op!=ASYNC_CLOSE && async.ioError ){
412     return async.ioError;
413   }
414   p = sqlite3_malloc(sizeof(AsyncWrite) + (zByte?nByte:0));
415   if( !p ){
416     return SQLITE_NOMEM;
417   }
418   p->op = op;
419   p->iOffset = iOffset;
420   p->nByte = nByte;
421   p->pFileData = pFileData;
422   p->pNext = 0;
423   if( zByte ){
424     p->zBuf = (char *)&p[1];
425     memcpy(p->zBuf, zByte, nByte);
426   }else{
427     p->zBuf = 0;
428   }
429   addAsyncWrite(p);
430   return SQLITE_OK;
431 }
432 
433 /*
434 ** Close the file. This just adds an entry to the write-op list, the file is
435 ** not actually closed.
436 */
437 static int asyncClose(sqlite3_file *pFile){
438   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
439   return addNewAsyncWrite(p, ASYNC_CLOSE, 0, 0, 0);
440 }
441 
442 /*
443 ** Implementation of sqlite3OsWrite() for asynchronous files. Instead of
444 ** writing to the underlying file, this function adds an entry to the end of
445 ** the global AsyncWrite list. Either SQLITE_OK or SQLITE_NOMEM may be
446 ** returned.
447 */
448 static int asyncWrite(sqlite3_file *pFile, const void *pBuf, int amt, i64 iOff){
449   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
450   return addNewAsyncWrite(p, ASYNC_WRITE, iOff, amt, pBuf);
451 }
452 
453 /*
454 ** Read data from the file. First we read from the filesystem, then adjust
455 ** the contents of the buffer based on ASYNC_WRITE operations in the
456 ** write-op queue.
457 **
458 ** This method holds the mutex from start to finish.
459 */
460 static int asyncRead(sqlite3_file *pFile, void *zOut, int iAmt, i64 iOffset){
461   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
462   int rc = SQLITE_OK;
463   i64 filesize;
464   int nRead;
465   sqlite3_file *pBase = p->pBaseRead;
466 
467   /* If an I/O error has previously occurred in this virtual file
468   ** system, then all subsequent operations fail.
469   */
470   if( async.ioError!=SQLITE_OK ){
471     return async.ioError;
472   }
473 
474   /* Grab the write queue mutex for the duration of the call */
475   pthread_mutex_lock(&async.queueMutex);
476 
477   if( pBase->pMethods ){
478     rc = sqlite3OsFileSize(pBase, &filesize);
479     if( rc!=SQLITE_OK ){
480       goto asyncread_out;
481     }
482     nRead = MIN(filesize - iOffset, iAmt);
483     if( nRead>0 ){
484       rc = sqlite3OsRead(pBase, zOut, nRead, iOffset);
485       ASYNC_TRACE(("READ %s %d bytes at %d\n", p->zName, nRead, iOffset));
486     }
487   }
488 
489   if( rc==SQLITE_OK ){
490     AsyncWrite *pWrite;
491 
492     for(pWrite=async.pQueueFirst; pWrite; pWrite = pWrite->pNext){
493       if( pWrite->pFileData==p && pWrite->op==ASYNC_WRITE ){
494         int iBeginOut = (pWrite->iOffset-iOffset);
495         int iBeginIn = -iBeginOut;
496         int nCopy;
497 
498         if( iBeginIn<0 ) iBeginIn = 0;
499         if( iBeginOut<0 ) iBeginOut = 0;
500         nCopy = MIN(pWrite->nByte-iBeginIn, iAmt-iBeginOut);
501 
502         if( nCopy>0 ){
503           memcpy(&((char *)zOut)[iBeginOut], &pWrite->zBuf[iBeginIn], nCopy);
504           ASYNC_TRACE(("OVERREAD %d bytes at %d\n", nCopy, iBeginOut+iOffset));
505         }
506       }
507     }
508   }
509 
510 asyncread_out:
511   pthread_mutex_unlock(&async.queueMutex);
512   return rc;
513 }
514 
515 /*
516 ** Truncate the file to nByte bytes in length. This just adds an entry to
517 ** the write-op list, no IO actually takes place.
518 */
519 static int asyncTruncate(sqlite3_file *pFile, i64 nByte){
520   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
521   return addNewAsyncWrite(p, ASYNC_TRUNCATE, nByte, 0, 0);
522 }
523 
524 /*
525 ** Sync the file. This just adds an entry to the write-op list, the
526 ** sync() is done later by sqlite3_async_flush().
527 */
528 static int asyncSync(sqlite3_file *pFile, int flags){
529   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
530   return addNewAsyncWrite(p, ASYNC_SYNC, 0, flags, 0);
531 }
532 
533 /*
534 ** Read the size of the file. First we read the size of the file system
535 ** entry, then adjust for any ASYNC_WRITE or ASYNC_TRUNCATE operations
536 ** currently in the write-op list.
537 **
538 ** This method holds the mutex from start to finish.
539 */
540 int asyncFileSize(sqlite3_file *pFile, i64 *piSize){
541   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
542   int rc = SQLITE_OK;
543   i64 s = 0;
544   sqlite3_file *pBase;
545 
546   pthread_mutex_lock(&async.queueMutex);
547 
548   /* Read the filesystem size from the base file. If pBaseRead is NULL, this
549   ** means the file hasn't been opened yet. In this case all relevant data
550   ** must be in the write-op queue anyway, so we can omit reading from the
551   ** file-system.
552   */
553   pBase = p->pBaseRead;
554   if( pBase->pMethods ){
555     rc = sqlite3OsFileSize(pBase, &s);
556   }
557 
558   if( rc==SQLITE_OK ){
559     AsyncWrite *pWrite;
560     for(pWrite=async.pQueueFirst; pWrite; pWrite = pWrite->pNext){
561       if( pWrite->pFileData==p ){
562         switch( pWrite->op ){
563           case ASYNC_WRITE:
564             s = MAX(pWrite->iOffset + (i64)(pWrite->nByte), s);
565             break;
566           case ASYNC_TRUNCATE:
567             s = MIN(s, pWrite->iOffset);
568             break;
569         }
570       }
571     }
572     *piSize = s;
573   }
574   pthread_mutex_unlock(&async.queueMutex);
575   return rc;
576 }
577 
578 /*
579 ** No disk locking is performed.  We keep track of locks locally in
580 ** the async.aLock hash table.  Locking should appear to work the same
581 ** as with standard (unmodified) SQLite as long as all connections
582 ** come from this one process.  Connections from external processes
583 ** cannot see our internal hash table (obviously) and will thus not
584 ** honor our locks.
585 */
586 static int asyncLock(sqlite3_file *pFile, int lockType){
587   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
588   ASYNC_TRACE(("LOCK %d (%s)\n", lockType, p->zName));
589   pthread_mutex_lock(&async.lockMutex);
590   sqlite3HashInsert(&async.aLock, p->zName, p->nName, (void*)lockType);
591   pthread_mutex_unlock(&async.lockMutex);
592   return SQLITE_OK;
593 }
594 static int asyncUnlock(sqlite3_file *pFile, int lockType){
595   return asyncLock(pFile, lockType);
596 }
597 
598 /*
599 ** This function is called when the pager layer first opens a database file
600 ** and is checking for a hot-journal.
601 */
602 static int asyncCheckReservedLock(sqlite3_file *pFile){
603   AsyncFileData *p = ((AsyncFile *)pFile)->pData;
604   int rc;
605   pthread_mutex_lock(&async.lockMutex);
606   rc = (int)sqlite3HashFind(&async.aLock, p->zName, p->nName);
607   pthread_mutex_unlock(&async.lockMutex);
608   ASYNC_TRACE(("CHECK-LOCK %d (%s)\n", rc, p->zName));
609   return rc>SHARED_LOCK;
610 }
611 
612 /*
613 ** This is a no-op, as the asynchronous backend does not support locking.
614 */
615 static int asyncBreakLock(sqlite3_file *id){
616   return SQLITE_OK;
617 }
618 
619 /*
620 ** This is broken. But sqlite3OsLockState() is only used for testing anyway.
621 */
622 static int asyncLockState(sqlite3_file *id){
623   return SQLITE_OK;
624 }
625 
626 /*
627 ** Return the device characteristics and sector-size of the device. It
628 ** is not tricky to implement these correctly, as this backend might
629 ** not have an open file handle at this point.
630 */
631 static int asyncSectorSize(sqlite3_file *pFile){
632   return 512;
633 }
634 static int asyncDeviceCharacteristics(sqlite3_file *pFile){
635   return 0;
636 }
637 
638 /*
639 ** Open a file.
640 */
641 static int asyncOpen(
642   sqlite3_vfs *pAsyncVfs,
643   const char *zName,
644   sqlite3_file *pFile,
645   int flags,
646   int *pOutFlags
647 ){
648   static sqlite3_io_methods async_methods = {
649     1,                               /* iVersion */
650     asyncClose,                      /* xClose */
651     asyncRead,                       /* xRead */
652     asyncWrite,                      /* xWrite */
653     asyncTruncate,                   /* xTruncate */
654     asyncSync,                       /* xSync */
655     asyncFileSize,                   /* xFileSize */
656     asyncLock,                       /* xLock */
657     asyncUnlock,                     /* xUnlock */
658     asyncCheckReservedLock,          /* xCheckReservedLock */
659     asyncBreakLock,                  /* xBreakLock */
660     asyncLockState,                  /* xLockState */
661     asyncSectorSize,                 /* xSectorSize */
662     asyncDeviceCharacteristics       /* xDeviceCharacteristics */
663   };
664 
665   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
666   AsyncFile *p = (AsyncFile *)pFile;
667   int nName = strlen(zName);;
668   int rc;
669   int nByte;
670   AsyncFileData *pData;
671 
672   nByte = (
673     sizeof(AsyncFileData) +        /* AsyncFileData structure */
674     2 * pVfs->szOsFile +           /* AsyncFileData.zName */
675     nName + 1                      /* AsyncFileData.pBaseRead and pBaseWrite */
676   );
677   pData = sqlite3_malloc(nByte);
678   if( !pData ){
679     return SQLITE_NOMEM;
680   }
681   memset(pData, 0, nByte);
682   pData->zName = (char *)&pData[1];
683   pData->nName = nName;
684   pData->pBaseRead = (sqlite3_file *)&pData->zName[nName+1];
685   pData->pBaseWrite = (sqlite3_file *)&pData->zName[nName+1+pVfs->szOsFile];
686   memcpy(pData->zName, zName, nName+1);
687 
688   if( flags&SQLITE_OPEN_EXCLUSIVE ){
689     rc = addNewAsyncWrite(pData, ASYNC_OPENEXCLUSIVE, (i64)flags, 0, 0);
690     if( pOutFlags ) *pOutFlags = flags;
691   }else{
692     rc = sqlite3OsOpen(pVfs, zName, pData->pBaseRead, flags, pOutFlags);
693     if( rc==SQLITE_OK && ((*pOutFlags)&SQLITE_OPEN_READWRITE) ){
694       rc = sqlite3OsOpen(pVfs, zName, pData->pBaseWrite, flags, 0);
695     }
696   }
697 
698   if( rc==SQLITE_OK ){
699     p->pMethod = &async_methods;
700     p->pData = pData;
701     incrOpenFileCount();
702   }else{
703     sqlite3OsClose(pData->pBaseRead);
704     sqlite3OsClose(pData->pBaseWrite);
705     sqlite3_free(pData);
706   }
707 
708   return rc;
709 }
710 
711 /*
712 ** Implementation of sqlite3OsDelete. Add an entry to the end of the
713 ** write-op queue to perform the delete.
714 */
715 static int asyncDelete(sqlite3_vfs *pAsyncVfs, const char *z, int syncDir){
716   return addNewAsyncWrite(0, ASYNC_DELETE, syncDir, strlen(z)+1, z);
717 }
718 
719 /*
720 ** Implementation of sqlite3OsAccess. This method holds the mutex from
721 ** start to finish.
722 */
723 static int asyncAccess(sqlite3_vfs *pAsyncVfs, const char *zName, int flags){
724   int ret;
725   AsyncWrite *p;
726   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
727 
728   assert(flags==SQLITE_ACCESS_READWRITE
729       || flags==SQLITE_ACCESS_READ
730       || flags==SQLITE_ACCESS_EXISTS
731   );
732 
733   pthread_mutex_lock(&async.queueMutex);
734   ret = sqlite3OsAccess(pVfs, zName, flags);
735   if( flags==SQLITE_ACCESS_EXISTS ){
736     for(p=async.pQueueFirst; p; p = p->pNext){
737       if( p->op==ASYNC_DELETE && 0==strcmp(p->zBuf, zName) ){
738         ret = 0;
739       }else if( p->op==ASYNC_OPENEXCLUSIVE
740              && 0==strcmp(p->pFileData->zName, zName)
741       ){
742         ret = 1;
743       }
744     }
745   }
746   ASYNC_TRACE(("ACCESS(%s): %s = %d\n",
747     flags==SQLITE_ACCESS_READWRITE?"read-write":
748     flags==SQLITE_ACCESS_READ?"read":"exists"
749     , zName, ret)
750   );
751   pthread_mutex_unlock(&async.queueMutex);
752   return ret;
753 }
754 
755 static int asyncGetTempName(sqlite3_vfs *pAsyncVfs, char *zBufOut){
756   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
757   return pVfs->xGetTempName(pVfs, zBufOut);
758 }
759 static int asyncFullPathname(
760   sqlite3_vfs *pAsyncVfs,
761   const char *zPath,
762   char *zPathOut
763 ){
764   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
765   return sqlite3OsFullPathname(pVfs, zPath, zPathOut);
766 }
767 static void *asyncDlOpen(sqlite3_vfs *pAsyncVfs, const char *zPath){
768   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
769   return pVfs->xDlOpen(pVfs, zPath);
770 }
771 static void asyncDlError(sqlite3_vfs *pAsyncVfs, int nByte, char *zErrMsg){
772   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
773   pVfs->xDlError(pVfs, nByte, zErrMsg);
774 }
775 static void *asyncDlSym(
776   sqlite3_vfs *pAsyncVfs,
777   void *pHandle,
778   const char *zSymbol
779 ){
780   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
781   return pVfs->xDlSym(pVfs, pHandle, zSymbol);
782 }
783 static void asyncDlClose(sqlite3_vfs *pAsyncVfs, void *pHandle){
784   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
785   pVfs->xDlClose(pVfs, pHandle);
786 }
787 static int asyncRandomness(sqlite3_vfs *pAsyncVfs, int nByte, char *zBufOut){
788   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
789   return pVfs->xRandomness(pVfs, nByte, zBufOut);
790 }
791 static int asyncSleep(sqlite3_vfs *pAsyncVfs, int nMicro){
792   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
793   return pVfs->xSleep(pVfs, nMicro);
794 }
795 static int asyncCurrentTime(sqlite3_vfs *pAsyncVfs, double *pTimeOut){
796   sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
797   return pVfs->xCurrentTime(pVfs, pTimeOut);
798 }
799 
800 static sqlite3_vfs async_vfs = {
801   1,                    /* iVersion */
802   sizeof(AsyncFile),    /* szOsFile */
803   0,                    /* mxPathname */
804   0,                    /* pNext */
805   "async",              /* zName */
806   0,                    /* pAppData */
807   asyncOpen,            /* xOpen */
808   asyncDelete,          /* xDelete */
809   asyncAccess,          /* xAccess */
810   asyncGetTempName,     /* xGetTempName */
811   asyncFullPathname,    /* xFullPathname */
812   asyncDlOpen,          /* xDlOpen */
813   asyncDlError,         /* xDlError */
814   asyncDlSym,           /* xDlSym */
815   asyncDlClose,         /* xDlClose */
816   asyncRandomness,      /* xDlError */
817   asyncSleep,           /* xDlSym */
818   asyncCurrentTime      /* xDlClose */
819 };
820 
821 /*
822 ** Call this routine to enable or disable the
823 ** asynchronous IO features implemented in this file.
824 **
825 ** This routine is not even remotely threadsafe.  Do not call
826 ** this routine while any SQLite database connections are open.
827 */
828 static void asyncEnable(int enable){
829   if( enable ){
830     if( !async_vfs.pAppData ){
831       async_vfs.pAppData = (void *)sqlite3_vfs_find(0);
832       async_vfs.mxPathname = ((sqlite3_vfs *)async_vfs.pAppData)->mxPathname;
833       sqlite3_vfs_register(&async_vfs, 1);
834       sqlite3HashInit(&async.aLock, SQLITE_HASH_BINARY, 1);
835     }
836   }else{
837     if( async_vfs.pAppData ){
838       sqlite3_vfs_unregister(&async_vfs);
839       async_vfs.pAppData = 0;
840       sqlite3HashClear(&async.aLock);
841     }
842   }
843 }
844 
845 /*
846 ** This procedure runs in a separate thread, reading messages off of the
847 ** write queue and processing them one by one.
848 **
849 ** If async.writerHaltNow is true, then this procedure exits
850 ** after processing a single message.
851 **
852 ** If async.writerHaltWhenIdle is true, then this procedure exits when
853 ** the write queue is empty.
854 **
855 ** If both of the above variables are false, this procedure runs
856 ** indefinately, waiting for operations to be added to the write queue
857 ** and processing them in the order in which they arrive.
858 **
859 ** An artifical delay of async.ioDelay milliseconds is inserted before
860 ** each write operation in order to simulate the effect of a slow disk.
861 **
862 ** Only one instance of this procedure may be running at a time.
863 */
864 static void *asyncWriterThread(void *NotUsed){
865   sqlite3_vfs *pVfs = (sqlite3_vfs *)(async_vfs.pAppData);
866   AsyncWrite *p = 0;
867   int rc = SQLITE_OK;
868   int holdingMutex = 0;
869 
870   if( pthread_mutex_trylock(&async.writerMutex) ){
871     return 0;
872   }
873   while( async.writerHaltNow==0 ){
874     sqlite3_file *pBase = 0;
875 
876     if( !holdingMutex ){
877       pthread_mutex_lock(&async.queueMutex);
878     }
879     while( (p = async.pQueueFirst)==0 ){
880       pthread_cond_broadcast(&async.emptySignal);
881       if( async.writerHaltWhenIdle ){
882         pthread_mutex_unlock(&async.queueMutex);
883         break;
884       }else{
885         ASYNC_TRACE(("IDLE\n"));
886         pthread_cond_wait(&async.queueSignal, &async.queueMutex);
887         ASYNC_TRACE(("WAKEUP\n"));
888       }
889     }
890     if( p==0 ) break;
891     holdingMutex = 1;
892 
893     /* Right now this thread is holding the mutex on the write-op queue.
894     ** Variable 'p' points to the first entry in the write-op queue. In
895     ** the general case, we hold on to the mutex for the entire body of
896     ** the loop.
897     **
898     ** However in the cases enumerated below, we relinquish the mutex,
899     ** perform the IO, and then re-request the mutex before removing 'p' from
900     ** the head of the write-op queue. The idea is to increase concurrency with
901     ** sqlite threads.
902     **
903     **     * An ASYNC_CLOSE operation.
904     **     * An ASYNC_OPENEXCLUSIVE operation. For this one, we relinquish
905     **       the mutex, call the underlying xOpenExclusive() function, then
906     **       re-aquire the mutex before seting the AsyncFile.pBaseRead
907     **       variable.
908     **     * ASYNC_SYNC and ASYNC_WRITE operations, if
909     **       SQLITE_ASYNC_TWO_FILEHANDLES was set at compile time and two
910     **       file-handles are open for the particular file being "synced".
911     */
912     if( async.ioError!=SQLITE_OK && p->op!=ASYNC_CLOSE ){
913       p->op = ASYNC_NOOP;
914     }
915     if( p->pFileData ){
916       pBase = p->pFileData->pBaseWrite;
917       if(
918         p->op==ASYNC_CLOSE ||
919         p->op==ASYNC_OPENEXCLUSIVE ||
920         (pBase->pMethods && (p->op==ASYNC_SYNC || p->op==ASYNC_WRITE) )
921       ){
922         pthread_mutex_unlock(&async.queueMutex);
923         holdingMutex = 0;
924       }
925       if( !pBase->pMethods ){
926         pBase = p->pFileData->pBaseRead;
927       }
928     }
929 
930     switch( p->op ){
931       case ASYNC_NOOP:
932         break;
933 
934       case ASYNC_WRITE:
935         assert( pBase );
936         ASYNC_TRACE(("WRITE %s %d bytes at %d\n",
937                 p->pFileData->zName, p->nByte, p->iOffset));
938         rc = sqlite3OsWrite(pBase, (void *)(p->zBuf), p->nByte, p->iOffset);
939         break;
940 
941       case ASYNC_SYNC:
942         assert( pBase );
943         ASYNC_TRACE(("SYNC %s\n", p->pFileData->zName));
944         rc = sqlite3OsSync(pBase, p->nByte);
945         break;
946 
947       case ASYNC_TRUNCATE:
948         assert( pBase );
949         ASYNC_TRACE(("TRUNCATE %s to %d bytes\n",
950                 p->pFileData->zName, p->iOffset));
951         rc = sqlite3OsTruncate(pBase, p->iOffset);
952         break;
953 
954       case ASYNC_CLOSE:
955         ASYNC_TRACE(("CLOSE %s\n", p->pFileData->zName));
956         sqlite3OsClose(p->pFileData->pBaseWrite);
957         sqlite3OsClose(p->pFileData->pBaseRead);
958         sqlite3_free(p->pFileData);
959         break;
960 
961       case ASYNC_DELETE:
962         ASYNC_TRACE(("DELETE %s\n", p->zBuf));
963         rc = sqlite3OsDelete(pVfs, p->zBuf, (int)p->iOffset);
964         break;
965 
966       case ASYNC_OPENEXCLUSIVE: {
967         int flags = (int)p->iOffset;
968         AsyncFileData *pData = p->pFileData;
969         ASYNC_TRACE(("OPEN %s flags=%d\n", p->zBuf, (int)p->iOffset));
970         assert(pData->pBaseRead->pMethods==0 && pData->pBaseWrite->pMethods==0);
971         rc = sqlite3OsOpen(pVfs, pData->zName, pData->pBaseRead, flags, 0);
972         assert( holdingMutex==0 );
973         pthread_mutex_lock(&async.queueMutex);
974         holdingMutex = 1;
975         break;
976       }
977 
978       default: assert(!"Illegal value for AsyncWrite.op");
979     }
980 
981     /* If we didn't hang on to the mutex during the IO op, obtain it now
982     ** so that the AsyncWrite structure can be safely removed from the
983     ** global write-op queue.
984     */
985     if( !holdingMutex ){
986       pthread_mutex_lock(&async.queueMutex);
987       holdingMutex = 1;
988     }
989     /* ASYNC_TRACE(("UNLINK %p\n", p)); */
990     if( p==async.pQueueLast ){
991       async.pQueueLast = 0;
992     }
993     async.pQueueFirst = p->pNext;
994     sqlite3_free(p);
995     assert( holdingMutex );
996 
997     /* An IO error has occured. We cannot report the error back to the
998     ** connection that requested the I/O since the error happened
999     ** asynchronously.  The connection has already moved on.  There
1000     ** really is nobody to report the error to.
1001     **
1002     ** The file for which the error occured may have been a database or
1003     ** journal file. Regardless, none of the currently queued operations
1004     ** associated with the same database should now be performed. Nor should
1005     ** any subsequently requested IO on either a database or journal file
1006     ** handle for the same database be accepted until the main database
1007     ** file handle has been closed and reopened.
1008     **
1009     ** Furthermore, no further IO should be queued or performed on any file
1010     ** handle associated with a database that may have been part of a
1011     ** multi-file transaction that included the database associated with
1012     ** the IO error (i.e. a database ATTACHed to the same handle at some
1013     ** point in time).
1014     */
1015     if( rc!=SQLITE_OK ){
1016       async.ioError = rc;
1017     }
1018 
1019     /* Drop the queue mutex before continuing to the next write operation
1020     ** in order to give other threads a chance to work with the write queue.
1021     */
1022     if( !async.pQueueFirst || !async.ioError ){
1023       sqlite3ApiExit(0, 0);
1024       pthread_mutex_unlock(&async.queueMutex);
1025       holdingMutex = 0;
1026       if( async.ioDelay>0 ){
1027         sqlite3OsSleep(pVfs, async.ioDelay);
1028       }else{
1029         sched_yield();
1030       }
1031     }
1032   }
1033 
1034   pthread_mutex_unlock(&async.writerMutex);
1035   return 0;
1036 }
1037 
1038 /**************************************************************************
1039 ** The remaining code defines a Tcl interface for testing the asynchronous
1040 ** IO implementation in this file.
1041 **
1042 ** To adapt the code to a non-TCL environment, delete or comment out
1043 ** the code that follows.
1044 */
1045 
1046 /*
1047 ** sqlite3async_enable ?YES/NO?
1048 **
1049 ** Enable or disable the asynchronous I/O backend.  This command is
1050 ** not thread-safe.  Do not call it while any database connections
1051 ** are open.
1052 */
1053 static int testAsyncEnable(
1054   void * clientData,
1055   Tcl_Interp *interp,
1056   int objc,
1057   Tcl_Obj *CONST objv[]
1058 ){
1059   if( objc!=1 && objc!=2 ){
1060     Tcl_WrongNumArgs(interp, 1, objv, "?YES/NO?");
1061     return TCL_ERROR;
1062   }
1063   if( objc==1 ){
1064     Tcl_SetObjResult(interp, Tcl_NewBooleanObj(async_vfs.pAppData!=0));
1065   }else{
1066     int en;
1067     if( Tcl_GetBooleanFromObj(interp, objv[1], &en) ) return TCL_ERROR;
1068     asyncEnable(en);
1069   }
1070   return TCL_OK;
1071 }
1072 
1073 /*
1074 ** sqlite3async_halt  "now"|"idle"|"never"
1075 **
1076 ** Set the conditions at which the writer thread will halt.
1077 */
1078 static int testAsyncHalt(
1079   void * clientData,
1080   Tcl_Interp *interp,
1081   int objc,
1082   Tcl_Obj *CONST objv[]
1083 ){
1084   const char *zCond;
1085   if( objc!=2 ){
1086     Tcl_WrongNumArgs(interp, 1, objv, "\"now\"|\"idle\"|\"never\"");
1087     return TCL_ERROR;
1088   }
1089   zCond = Tcl_GetString(objv[1]);
1090   if( strcmp(zCond, "now")==0 ){
1091     async.writerHaltNow = 1;
1092     pthread_cond_broadcast(&async.queueSignal);
1093   }else if( strcmp(zCond, "idle")==0 ){
1094     async.writerHaltWhenIdle = 1;
1095     async.writerHaltNow = 0;
1096     pthread_cond_broadcast(&async.queueSignal);
1097   }else if( strcmp(zCond, "never")==0 ){
1098     async.writerHaltWhenIdle = 0;
1099     async.writerHaltNow = 0;
1100   }else{
1101     Tcl_AppendResult(interp,
1102       "should be one of: \"now\", \"idle\", or \"never\"", (char*)0);
1103     return TCL_ERROR;
1104   }
1105   return TCL_OK;
1106 }
1107 
1108 /*
1109 ** sqlite3async_delay ?MS?
1110 **
1111 ** Query or set the number of milliseconds of delay in the writer
1112 ** thread after each write operation.  The default is 0.  By increasing
1113 ** the memory delay we can simulate the effect of slow disk I/O.
1114 */
1115 static int testAsyncDelay(
1116   void * clientData,
1117   Tcl_Interp *interp,
1118   int objc,
1119   Tcl_Obj *CONST objv[]
1120 ){
1121   if( objc!=1 && objc!=2 ){
1122     Tcl_WrongNumArgs(interp, 1, objv, "?MS?");
1123     return TCL_ERROR;
1124   }
1125   if( objc==1 ){
1126     Tcl_SetObjResult(interp, Tcl_NewIntObj(async.ioDelay));
1127   }else{
1128     int ioDelay;
1129     if( Tcl_GetIntFromObj(interp, objv[1], &ioDelay) ) return TCL_ERROR;
1130     async.ioDelay = ioDelay;
1131   }
1132   return TCL_OK;
1133 }
1134 
1135 /*
1136 ** sqlite3async_start
1137 **
1138 ** Start a new writer thread.
1139 */
1140 static int testAsyncStart(
1141   void * clientData,
1142   Tcl_Interp *interp,
1143   int objc,
1144   Tcl_Obj *CONST objv[]
1145 ){
1146   pthread_t x;
1147   int rc;
1148   rc = pthread_create(&x, 0, asyncWriterThread, 0);
1149   if( rc ){
1150     Tcl_AppendResult(interp, "failed to create the thread", 0);
1151     return TCL_ERROR;
1152   }
1153   pthread_detach(x);
1154   return TCL_OK;
1155 }
1156 
1157 /*
1158 ** sqlite3async_wait
1159 **
1160 ** Wait for the current writer thread to terminate.
1161 **
1162 ** If the current writer thread is set to run forever then this
1163 ** command would block forever.  To prevent that, an error is returned.
1164 */
1165 static int testAsyncWait(
1166   void * clientData,
1167   Tcl_Interp *interp,
1168   int objc,
1169   Tcl_Obj *CONST objv[]
1170 ){
1171   int cnt = 10;
1172   if( async.writerHaltNow==0 && async.writerHaltWhenIdle==0 ){
1173     Tcl_AppendResult(interp, "would block forever", (char*)0);
1174     return TCL_ERROR;
1175   }
1176 
1177   while( cnt-- && !pthread_mutex_trylock(&async.writerMutex) ){
1178     pthread_mutex_unlock(&async.writerMutex);
1179     sched_yield();
1180   }
1181   if( cnt>=0 ){
1182     ASYNC_TRACE(("WAIT\n"));
1183     pthread_mutex_lock(&async.queueMutex);
1184     pthread_cond_broadcast(&async.queueSignal);
1185     pthread_mutex_unlock(&async.queueMutex);
1186     pthread_mutex_lock(&async.writerMutex);
1187     pthread_mutex_unlock(&async.writerMutex);
1188   }else{
1189     ASYNC_TRACE(("NO-WAIT\n"));
1190   }
1191   return TCL_OK;
1192 }
1193 
1194 
1195 #endif  /* OS_UNIX and SQLITE_THREADSAFE and defined(SQLITE_ENABLE_REDEF_IO) */
1196 
1197 /*
1198 ** This routine registers the custom TCL commands defined in this
1199 ** module.  This should be the only procedure visible from outside
1200 ** of this module.
1201 */
1202 int Sqlitetestasync_Init(Tcl_Interp *interp){
1203 #if OS_UNIX && SQLITE_THREADSAFE && defined(SQLITE_ENABLE_REDEF_IO)
1204   Tcl_CreateObjCommand(interp,"sqlite3async_enable",testAsyncEnable,0,0);
1205   Tcl_CreateObjCommand(interp,"sqlite3async_halt",testAsyncHalt,0,0);
1206   Tcl_CreateObjCommand(interp,"sqlite3async_delay",testAsyncDelay,0,0);
1207   Tcl_CreateObjCommand(interp,"sqlite3async_start",testAsyncStart,0,0);
1208   Tcl_CreateObjCommand(interp,"sqlite3async_wait",testAsyncWait,0,0);
1209   Tcl_LinkVar(interp, "sqlite3async_trace",
1210       (char*)&sqlite3async_trace, TCL_LINK_INT);
1211 #endif  /* OS_UNIX and SQLITE_THREADSAFE and defined(SQLITE_ENABLE_REDEF_IO) */
1212   return TCL_OK;
1213 }
1214