mirror of
https://github.com/sqlite/sqlite.git
synced 2025-10-25 20:58:26 +03:00
Documentation updates. Fix to date.c. But most importantly: database
connections are now allowed to change threads as long as they are not holding a lock. (CVS 2944) FossilOrigin-Name: 03c422ecb508dd84dfafc8b7a0b790a43f5dadda
This commit is contained in:
121
src/os_unix.c
121
src/os_unix.c
@@ -165,9 +165,10 @@ struct unixFile {
|
||||
** to another. This logic makes sure a user does not try to do that
|
||||
** by mistake.
|
||||
*/
|
||||
#if defined(SQLITE_UNIX_THREADS) && !defined(SQLITE_ALLOW_XTHREAD_CONNECTIONS)
|
||||
#if defined(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 && \
|
||||
!pthread_equal((X)->tid, pthread_self()))
|
||||
#else
|
||||
# define SET_THREADID(X)
|
||||
# define CHECK_THREADID(X) 0
|
||||
@@ -348,7 +349,11 @@ static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
|
||||
** 1: Yes. Threads can override each others locks.
|
||||
** -1: We don't know yet.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int threadsOverrideEachOthersLocks = -1;
|
||||
#else
|
||||
static int threadsOverrideEachOthersLocks = -1;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This structure holds information passed into individual test
|
||||
@@ -465,6 +470,7 @@ static void testThreadLockingBehavior(fd_orig){
|
||||
** Release a lockInfo structure previously allocated by findLockInfo().
|
||||
*/
|
||||
static void releaseLockInfo(struct lockInfo *pLock){
|
||||
assert( sqlite3OsInMutex() );
|
||||
pLock->nRef--;
|
||||
if( pLock->nRef==0 ){
|
||||
sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
|
||||
@@ -476,6 +482,7 @@ static void releaseLockInfo(struct lockInfo *pLock){
|
||||
** Release a openCnt structure previously allocated by findLockInfo().
|
||||
*/
|
||||
static void releaseOpenCnt(struct openCnt *pOpen){
|
||||
assert( sqlite3OsInMutex() );
|
||||
pOpen->nRef--;
|
||||
if( pOpen->nRef==0 ){
|
||||
sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
|
||||
@@ -486,8 +493,8 @@ static void releaseOpenCnt(struct openCnt *pOpen){
|
||||
|
||||
/*
|
||||
** Given a file descriptor, locate lockInfo and openCnt structures that
|
||||
** describes that file descriptor. Create a new ones if necessary. The
|
||||
** return values might be unset if an error occurs.
|
||||
** describes that file descriptor. Create new ones if necessary. The
|
||||
** return values might be uninitialized if an error occurs.
|
||||
**
|
||||
** Return the number of errors.
|
||||
*/
|
||||
@@ -505,6 +512,7 @@ static int findLockInfo(
|
||||
rc = fstat(fd, &statbuf);
|
||||
if( rc!=0 ) return 1;
|
||||
|
||||
assert( sqlite3OsInMutex() );
|
||||
memset(&key1, 0, sizeof(key1));
|
||||
key1.dev = statbuf.st_dev;
|
||||
key1.ino = statbuf.st_ino;
|
||||
@@ -540,37 +548,76 @@ static int findLockInfo(
|
||||
pLock->nRef++;
|
||||
}
|
||||
*ppLock = pLock;
|
||||
pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
|
||||
if( pOpen==0 ){
|
||||
struct openCnt *pOld;
|
||||
pOpen = sqliteMallocRaw( sizeof(*pOpen) );
|
||||
if( ppOpen!=0 ){
|
||||
pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
|
||||
if( pOpen==0 ){
|
||||
releaseLockInfo(pLock);
|
||||
rc = 1;
|
||||
goto exit_findlockinfo;
|
||||
struct openCnt *pOld;
|
||||
pOpen = sqliteMallocRaw( sizeof(*pOpen) );
|
||||
if( pOpen==0 ){
|
||||
releaseLockInfo(pLock);
|
||||
rc = 1;
|
||||
goto exit_findlockinfo;
|
||||
}
|
||||
pOpen->key = key2;
|
||||
pOpen->nRef = 1;
|
||||
pOpen->nLock = 0;
|
||||
pOpen->nPending = 0;
|
||||
pOpen->aPending = 0;
|
||||
pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
|
||||
if( pOld!=0 ){
|
||||
assert( pOld==pOpen );
|
||||
sqliteFree(pOpen);
|
||||
releaseLockInfo(pLock);
|
||||
rc = 1;
|
||||
goto exit_findlockinfo;
|
||||
}
|
||||
}else{
|
||||
pOpen->nRef++;
|
||||
}
|
||||
pOpen->key = key2;
|
||||
pOpen->nRef = 1;
|
||||
pOpen->nLock = 0;
|
||||
pOpen->nPending = 0;
|
||||
pOpen->aPending = 0;
|
||||
pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
|
||||
if( pOld!=0 ){
|
||||
assert( pOld==pOpen );
|
||||
sqliteFree(pOpen);
|
||||
releaseLockInfo(pLock);
|
||||
rc = 1;
|
||||
goto exit_findlockinfo;
|
||||
}
|
||||
}else{
|
||||
pOpen->nRef++;
|
||||
*ppOpen = pOpen;
|
||||
}
|
||||
*ppOpen = pOpen;
|
||||
|
||||
exit_findlockinfo:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** If we are currently in a different thread than the thread that the
|
||||
** unixFile argument belongs to, then transfer ownership of the unixFile
|
||||
** over to the current thread.
|
||||
**
|
||||
** A unixFile is only owned by a thread on systems where one thread is
|
||||
** unable to override locks created by a different thread. RedHat9 is
|
||||
** an example of such a system.
|
||||
**
|
||||
** Ownership transfer is only allowed if the unixFile is currently unlocked.
|
||||
** If the unixFile is locked and an ownership is wrong, then return
|
||||
** SQLITE_MISUSE. Otherwise return SQLITE_OK.
|
||||
*/
|
||||
#ifdef SQLITE_UNIX_THREADS
|
||||
static int transferOwnership(unixFile *pFile){
|
||||
pthread_t hSelf;
|
||||
if( threadsOverrideEachOthersLocks ){
|
||||
/* Ownership transfers not needed on this system */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
hSelf = pthread_self();
|
||||
if( pthread_equal(pFile->tid, hSelf) ){
|
||||
/* We are still in the same thread */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( pFile->locktype!=NO_LOCK ){
|
||||
/* We cannot change ownership while we are holding a lock! */
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
pFile->tid = hSelf;
|
||||
releaseLockInfo(pFile->pLock);
|
||||
return findLockInfo(pFile->h, &pFile->pLock, 0);
|
||||
}
|
||||
#else
|
||||
# define transferOwnership(X) SQLITE_OK
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Delete the named file
|
||||
*/
|
||||
@@ -1047,7 +1094,6 @@ static int unixCheckReservedLock(OsFile *id){
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
|
||||
assert( pFile );
|
||||
if( CHECK_THREADID(pFile) ) return SQLITE_MISUSE;
|
||||
sqlite3OsEnterMutex(); /* Because pFile->pLock is shared across threads */
|
||||
|
||||
/* Check if a thread in this process holds such a lock */
|
||||
@@ -1166,7 +1212,6 @@ static int unixLock(OsFile *id, int locktype){
|
||||
TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h,
|
||||
locktypeName(locktype), locktypeName(pFile->locktype),
|
||||
locktypeName(pLock->locktype), pLock->cnt , getpid());
|
||||
if( CHECK_THREADID(pFile) ) 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
|
||||
@@ -1188,6 +1233,14 @@ static int unixLock(OsFile *id, int locktype){
|
||||
*/
|
||||
sqlite3OsEnterMutex();
|
||||
|
||||
/* Make sure the current thread owns the pFile.
|
||||
*/
|
||||
rc = transferOwnership(pFile);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsLeaveMutex();
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* If some thread using this PID has a lock via a different OsFile*
|
||||
** handle that precludes the requested lock, return BUSY.
|
||||
*/
|
||||
@@ -1324,12 +1377,12 @@ static int unixUnlock(OsFile *id, int locktype){
|
||||
assert( pFile );
|
||||
TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype,
|
||||
pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid());
|
||||
if( CHECK_THREADID(pFile) ) return SQLITE_MISUSE;
|
||||
|
||||
assert( locktype<=SHARED_LOCK );
|
||||
if( pFile->locktype<=locktype ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( CHECK_THREADID(pFile) ) return SQLITE_MISUSE;
|
||||
sqlite3OsEnterMutex();
|
||||
pLock = pFile->pLock;
|
||||
assert( pLock->cnt!=0 );
|
||||
@@ -1401,9 +1454,11 @@ static int unixUnlock(OsFile *id, int locktype){
|
||||
*/
|
||||
static int unixClose(OsFile **pId){
|
||||
unixFile *id = (unixFile*)*pId;
|
||||
int rc;
|
||||
|
||||
if( !id ) return SQLITE_OK;
|
||||
if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
|
||||
unixUnlock(*pId, NO_LOCK);
|
||||
rc = unixUnlock(*pId, NO_LOCK);
|
||||
if( rc ) return rc;
|
||||
if( id->dirfd>=0 ) close(id->dirfd);
|
||||
id->dirfd = -1;
|
||||
sqlite3OsEnterMutex();
|
||||
@@ -1516,8 +1571,10 @@ static int allocateUnixFile(unixFile *pInit, OsFile **pId){
|
||||
pNew = sqliteMalloc( sizeof(unixFile) );
|
||||
if( pNew==0 ){
|
||||
close(pInit->h);
|
||||
sqlite3OsEnterMutex();
|
||||
releaseLockInfo(pInit->pLock);
|
||||
releaseOpenCnt(pInit->pOpen);
|
||||
sqlite3OsLeaveMutex();
|
||||
*pId = 0;
|
||||
return SQLITE_NOMEM;
|
||||
}else{
|
||||
|
||||
Reference in New Issue
Block a user