Hello, In attachement, there's a diff/patch against os_unix.c in version 3.2.5. Its allows threads to access successively to a DB handle and remove the heavy restriction of the SQLITE_MISUSE. In case of simultaneous access, threads get SQLITE_BUSY until the OsFile is unlocked.
I test it a bit, it works well with my code and my bad unix threaded file locks. Can anybody test it too? Best regards, Mon, Sep 05, 2005 at 02:18:41PM -0400: D. Richard Hipp wrote: > On Mon, 2005-09-05 at 19:58 +0200, René Tegel wrote: > > > As far as i can tell now the windows version of 3.2.5 seems not affected. > > > > The restriction that a DB handle can only be used from a single > thread is currently only enforced on Unix, because Unix boxes > are the only place where using DB handles in multiple threads is > a problem. -- Guillaume FOUGNIES Eulerian Technologies
--- ../../sqlite-3.2.5/src/os_unix.c 2005-08-25 14:48:33.000000000 +0200 +++ os_unix.c 2005-09-07 20:17:38.000000000 +0200 @@ -82,7 +82,8 @@ */ #ifdef SQLITE_UNIX_THREADS # define SET_THREADID(X) X->tid = pthread_self() -# define CHECK_THREADID(X) (!pthread_equal(X->tid, pthread_self())) +# define CHECK_THREADID(X) ( threadsOverrideEachOthersLocks>0 && \ + check_threadid(X) ) #else # define SET_THREADID(X) # define CHECK_THREADID(X) 0 @@ -275,6 +276,26 @@ struct threadTestData { int result; /* Result of the locking operation */ }; +/* +** Check if the thread is allowed to use the OsFile +** +** If another thread opened the OsFile and this OsFile +** is now lock clear, the new thread is allowed to work +** with. Its tid is set. +** This routine is be protected by the global mutex. +*/ +static int check_threadid(OsFile *id) { + if ( pthread_equal(id->tid, pthread_self()) ) { + return 0; + } + if ( id->pLock->locktype == NO_LOCK ) { + SET_THREADID(id); + return 0; + } + return 1; +} + + #ifdef SQLITE_LOCK_TRACE /* ** Print out information about all locking operations. @@ -914,9 +935,14 @@ int sqlite3OsCheckReservedLock(OsFile *i int r = 0; assert( id->isOpen ); - if( CHECK_THREADID(id) ) return SQLITE_MISUSE; sqlite3OsEnterMutex(); /* Needed because id->pLock is shared across threads */ +#ifdef SQLITE_UNIX_THREADS + if( CHECK_THREADID(id) ) { + r = 1; + } +#endif + /* Check if a thread in this process holds such a lock */ if( id->pLock->locktype>SHARED_LOCK ){ r = 1; @@ -1032,7 +1058,6 @@ int sqlite3OsLock(OsFile *id, int lockty TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype), locktypeName(id->locktype), locktypeName(pLock->locktype), pLock->cnt ,getpid() ); - if( CHECK_THREADID(id) ) return SQLITE_MISUSE; /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as @@ -1053,6 +1078,13 @@ int sqlite3OsLock(OsFile *id, int lockty */ sqlite3OsEnterMutex(); +#ifdef SQLITE_UNIX_THREADS + if( CHECK_THREADID(id) ){ + rc = SQLITE_BUSY; + goto end_lock; + } +#endif + /* If some thread using this PID has a lock via a different OsFile* ** handle that precludes the requested lock, return BUSY. */ @@ -1188,13 +1220,20 @@ int sqlite3OsUnlock(OsFile *id, int lock assert( id->isOpen ); TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype, id->pLock->locktype, id->pLock->cnt, getpid()); - if( CHECK_THREADID(id) ) return SQLITE_MISUSE; assert( locktype<=SHARED_LOCK ); if( id->locktype<=locktype ){ return SQLITE_OK; } sqlite3OsEnterMutex(); + +#ifdef SQLITE_UNIX_THREADS + if( CHECK_THREADID(id) ){ + /* This should never happen */ + rc = SQLITE_IOERR; + } +#endif + pLock = id->pLock; assert( pLock->cnt!=0 ); if( id->locktype>SHARED_LOCK ){ @@ -1265,7 +1304,6 @@ int sqlite3OsUnlock(OsFile *id, int lock */ int sqlite3OsClose(OsFile *id){ if( !id->isOpen ) return SQLITE_OK; - if( CHECK_THREADID(id) ) return SQLITE_MISUSE; sqlite3OsUnlock(id, NO_LOCK); if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1;