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;