mirror of
https://github.com/sqlite/sqlite.git
synced 2025-12-21 13:38:01 +03:00
When SQLITE_ENABLE_SETLK_TIMEOUT is defined, use a separate mutex in os_unix.c for each shm locking slot.
FossilOrigin-Name: 4098df9652d90f2d22d5591d915d672c5413471f7916223510ba6fd932bfdd36
This commit is contained in:
17
manifest
17
manifest
@@ -1,5 +1,5 @@
|
||||
C Fix\sharmless\scompiler\swarnings\sin\sdebugging\scode.
|
||||
D 2023-11-17T12:22:42.597
|
||||
C When\sSQLITE_ENABLE_SETLK_TIMEOUT\sis\sdefined,\suse\sa\sseparate\smutex\sin\sos_unix.c\sfor\seach\sshm\slocking\sslot.
|
||||
D 2023-11-17T17:10:37.075
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -709,7 +709,7 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
|
||||
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
|
||||
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
|
||||
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
|
||||
F src/os_unix.c f8a557ff5b387ec599e8b84b7341e5a45ebdd579da03788364a34b9a9567faeb
|
||||
F src/os_unix.c 1f6a930e8469b3709728690d089b55deb2fe605ba860941ddc21a2345e51bce4
|
||||
F src/os_win.c 4a50a154aeebc66a1f8fb79c1ff6dd5fe3d005556533361e0d460d41cb6a45a8
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 987ab3a2cd9065d62e9955474470ff733445e2357432a67e3d0f5a8f9313e334
|
||||
@@ -2140,8 +2140,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P a9443dbfbe25e588b4adddde664ddf482f19f71c704fbf356d49cf3a6135e7fb
|
||||
R dc0c90fa6e9a7208b4b533ec9a5980a8
|
||||
U drh
|
||||
Z 5cf7a41ba5c0eb3c7c4392bc0e2744d2
|
||||
P ce6a75622ea5bca517bc6613e738aa670c9e1dd863596220eded5c2379c616c7
|
||||
R 277be03c0e13cb54ac8c8a3d23aba815
|
||||
T *branch * unix-setlk-timeout-mutexes
|
||||
T *sym-unix-setlk-timeout-mutexes *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z 8cc8841ac15d12b07622be01120eb3c1
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1 +1 @@
|
||||
ce6a75622ea5bca517bc6613e738aa670c9e1dd863596220eded5c2379c616c7
|
||||
4098df9652d90f2d22d5591d915d672c5413471f7916223510ba6fd932bfdd36
|
||||
187
src/os_unix.c
187
src/os_unix.c
@@ -4313,6 +4313,25 @@ static int unixGetpagesize(void){
|
||||
** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and
|
||||
** unixMutexHeld() is true when reading or writing any other field
|
||||
** in this structure.
|
||||
**
|
||||
** aLock[SQLITE_SHM_NLOCK]:
|
||||
** This array records the various locks held by clients on each of the
|
||||
** SQLITE_SHM_NLOCK slots. If the aLock[] entry is set to 0, then no
|
||||
** locks are held by the process on this slot. If it is set to -1, then
|
||||
** some client holds an EXCLUSIVE lock on the locking slot. If the aLock[]
|
||||
** value is set to a positive value, then it is the number of shared
|
||||
** locks currently held on the slot.
|
||||
**
|
||||
** aMutex[SQLITE_SHM_NLOCK]:
|
||||
** Normally, when SQLITE_ENABLE_SETLK_TIMEOUT is not defined, mutex
|
||||
** pShmMutex is used to protect the aLock[] array and the right to
|
||||
** call fcntl() on unixShmNode.hShm to obtain or release locks.
|
||||
**
|
||||
** If SQLITE_ENABLE_SETLK_TIMEOUT is defined though, we use an array
|
||||
** of mutexes - one for each locking slot. To read or write locking
|
||||
** slot aLock[iSlot], the caller must hold the corresponding mutex
|
||||
** aMutex[iSlot]. Similarly, to call fcntl() to obtain or release a
|
||||
** lock corresponding to slot iSlot, mutex aMutex[iSlot] must be held.
|
||||
*/
|
||||
struct unixShmNode {
|
||||
unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
|
||||
@@ -4326,10 +4345,11 @@ struct unixShmNode {
|
||||
char **apRegion; /* Array of mapped shared-memory regions */
|
||||
int nRef; /* Number of unixShm objects pointing to this */
|
||||
unixShm *pFirst; /* All unixShm objects pointing to this */
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK];
|
||||
#endif
|
||||
int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */
|
||||
#ifdef SQLITE_DEBUG
|
||||
u8 exclMask; /* Mask of exclusive locks held */
|
||||
u8 sharedMask; /* Mask of shared locks held */
|
||||
u8 nextShmId; /* Next available unixShm.id value */
|
||||
#endif
|
||||
};
|
||||
@@ -4412,16 +4432,29 @@ static int unixShmSystemLock(
|
||||
struct flock f; /* The posix advisory locking structure */
|
||||
int rc = SQLITE_OK; /* Result code form fcntl() */
|
||||
|
||||
/* Access to the unixShmNode object is serialized by the caller */
|
||||
pShmNode = pFile->pInode->pShmNode;
|
||||
assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) );
|
||||
assert( pShmNode->nRef>0 || unixMutexHeld() );
|
||||
|
||||
/* Assert that the correct mutex or mutexes are held. */
|
||||
if( pShmNode->nRef==0 ){
|
||||
assert( ofst==UNIX_SHM_DMS && n==1 && unixMutexHeld() );
|
||||
}else{
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
int ii;
|
||||
for(ii=ofst-UNIX_SHM_BASE; ii<ofst-UNIX_SHM_BASE+n; ii++){
|
||||
assert( sqlite3_mutex_held(pShmNode->aMutex[ii]) );
|
||||
}
|
||||
#else
|
||||
assert( sqlite3_mutex_held(pShmNode->pShmMutex) );
|
||||
assert( pShmNode->nRef>0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Shared locks never span more than one byte */
|
||||
assert( n==1 || lockType!=F_RDLCK );
|
||||
|
||||
/* Locks are within range */
|
||||
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
|
||||
assert( ofst>=UNIX_SHM_BASE && ofst<=(UNIX_SHM_DMS+SQLITE_SHM_NLOCK) );
|
||||
|
||||
if( pShmNode->hShm>=0 ){
|
||||
int res;
|
||||
@@ -4440,39 +4473,28 @@ static int unixShmSystemLock(
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the global lock state and do debug tracing */
|
||||
/* Do debug tracing */
|
||||
#ifdef SQLITE_DEBUG
|
||||
{ u16 mask;
|
||||
OSTRACE(("SHM-LOCK "));
|
||||
mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<<ofst);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( lockType==F_UNLCK ){
|
||||
OSTRACE(("unlock %d ok", ofst));
|
||||
pShmNode->exclMask &= ~mask;
|
||||
pShmNode->sharedMask &= ~mask;
|
||||
OSTRACE(("unlock %d..%d ok\n", ofst, ofst+n-1));
|
||||
}else if( lockType==F_RDLCK ){
|
||||
OSTRACE(("read-lock %d ok", ofst));
|
||||
pShmNode->exclMask &= ~mask;
|
||||
pShmNode->sharedMask |= mask;
|
||||
OSTRACE(("read-lock %d..%d ok\n", ofst, ofst+n-1));
|
||||
}else{
|
||||
assert( lockType==F_WRLCK );
|
||||
OSTRACE(("write-lock %d ok", ofst));
|
||||
pShmNode->exclMask |= mask;
|
||||
pShmNode->sharedMask &= ~mask;
|
||||
OSTRACE(("write-lock %d..%d ok\n", ofst, ofst+n-1));
|
||||
}
|
||||
}else{
|
||||
if( lockType==F_UNLCK ){
|
||||
OSTRACE(("unlock %d failed", ofst));
|
||||
OSTRACE(("unlock %d..%d failed\n", ofst, ofst+n-1));
|
||||
}else if( lockType==F_RDLCK ){
|
||||
OSTRACE(("read-lock failed"));
|
||||
OSTRACE(("read-lock %d..%d failed\n", ofst, ofst+n-1));
|
||||
}else{
|
||||
assert( lockType==F_WRLCK );
|
||||
OSTRACE(("write-lock %d failed", ofst));
|
||||
OSTRACE(("write-lock %d..%d failed\n", ofst, ofst+n-1));
|
||||
}
|
||||
}
|
||||
OSTRACE((" - afterwards %03x,%03x\n",
|
||||
pShmNode->sharedMask, pShmNode->exclMask));
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
@@ -4509,6 +4531,11 @@ static void unixShmPurge(unixFile *pFd){
|
||||
int i;
|
||||
assert( p->pInode==pFd->pInode );
|
||||
sqlite3_mutex_free(p->pShmMutex);
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
for(i=0; i<SQLITE_SHM_NLOCK; i++){
|
||||
sqlite3_mutex_free(p->aMutex[i]);
|
||||
}
|
||||
#endif
|
||||
for(i=0; i<p->nRegion; i+=nShmPerMap){
|
||||
if( p->hShm>=0 ){
|
||||
osMunmap(p->apRegion[i], p->szRegion);
|
||||
@@ -4689,6 +4716,18 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto shm_open_err;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
{
|
||||
int ii;
|
||||
for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
|
||||
pShmNode->aMutex[ii] = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||
if( pShmNode->aMutex[ii]==0 ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto shm_open_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if( pInode->bProcessLock==0 ){
|
||||
@@ -4910,9 +4949,11 @@ shmpage_out:
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
static int assertLockingArrayOk(unixShmNode *pShmNode){
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
return 1;
|
||||
#else
|
||||
unixShm *pX;
|
||||
int aLock[SQLITE_SHM_NLOCK];
|
||||
assert( sqlite3_mutex_held(pShmNode->pShmMutex) );
|
||||
|
||||
memset(aLock, 0, sizeof(aLock));
|
||||
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
||||
@@ -4930,13 +4971,14 @@ static int assertLockingArrayOk(unixShmNode *pShmNode){
|
||||
|
||||
assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) );
|
||||
return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Change the lock state for a shared-memory segment.
|
||||
**
|
||||
** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
|
||||
** Note that the relationship between SHARED and EXCLUSIVE locks is a little
|
||||
** different here than in posix. In xShmLock(), one can go from unlocked
|
||||
** to shared and back or from unlocked to exclusive and back. But one may
|
||||
** not go from shared to exclusive or from exclusive to shared.
|
||||
@@ -4951,7 +4993,7 @@ static int unixShmLock(
|
||||
unixShm *p; /* The shared memory being locked */
|
||||
unixShmNode *pShmNode; /* The underlying file iNode */
|
||||
int rc = SQLITE_OK; /* Result code */
|
||||
u16 mask; /* Mask of locks to take or release */
|
||||
u16 mask = (1<<(ofst+n)) - (1<<ofst); /* Mask of locks to take or release */
|
||||
int *aLock;
|
||||
|
||||
p = pDbFd->pShm;
|
||||
@@ -4997,18 +5039,51 @@ static int unixShmLock(
|
||||
}
|
||||
#endif
|
||||
|
||||
mask = (1<<(ofst+n)) - (1<<ofst);
|
||||
assert( n>1 || mask==(1<<ofst) );
|
||||
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
||||
assert( assertLockingArrayOk(pShmNode) );
|
||||
if( flags & SQLITE_SHM_UNLOCK ){
|
||||
if( (p->exclMask|p->sharedMask) & mask ){
|
||||
int ii;
|
||||
int bUnlock = 1;
|
||||
/* Check if there is any work to do. There are three cases:
|
||||
**
|
||||
** a) An unlock operation where there are locks to unlock,
|
||||
** b) An shared lock where the requested lock is not already held
|
||||
** c) An exclusive lock where the requested lock is not already held
|
||||
**
|
||||
** The SQLite core never requests an exclusive lock that it already holds.
|
||||
** This is assert()ed below.
|
||||
*/
|
||||
assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)
|
||||
|| 0==(p->exclMask & mask)
|
||||
);
|
||||
if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask))
|
||||
|| (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask))
|
||||
|| (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK))
|
||||
){
|
||||
|
||||
for(ii=ofst; ii<ofst+n; ii++){
|
||||
if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){
|
||||
/* Take the required mutexes */
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
int iMutex;
|
||||
for(iMutex=ofst; iMutex<ofst+n; iMutex++){
|
||||
sqlite3_mutex_enter(pShmNode->aMutex[iMutex]);
|
||||
}
|
||||
#else
|
||||
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
||||
#endif
|
||||
|
||||
if( flags & SQLITE_SHM_UNLOCK ){
|
||||
/* Case (a) - unlock. */
|
||||
int bUnlock = 1;
|
||||
assert( (p->exclMask & p->sharedMask)==0 );
|
||||
assert( (flags & SQLITE_SHM_EXCLUSIVE)==0 || (p->exclMask & mask)==mask );
|
||||
assert( (flags & SQLITE_SHM_SHARED)==0 || (p->sharedMask & mask)==mask );
|
||||
|
||||
/* If this is a SHARED lock being unlocked, it is possible that other
|
||||
** clients within this process are holding the same SHARED lock. In
|
||||
** this case, set bUnlock to 0 so that the posix lock is not removed
|
||||
** from the file-descriptor below. */
|
||||
if( flags & SQLITE_SHM_SHARED ){
|
||||
assert( n==1 );
|
||||
assert( aLock[ofst]>=1 );
|
||||
if( aLock[ofst]>1 ){
|
||||
bUnlock = 0;
|
||||
aLock[ofst]--;
|
||||
p->sharedMask &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5016,23 +5091,15 @@ static int unixShmLock(
|
||||
rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(&aLock[ofst], 0, sizeof(int)*n);
|
||||
}
|
||||
}else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
|
||||
assert( n==1 && aLock[ofst]>1 );
|
||||
aLock[ofst]--;
|
||||
}
|
||||
|
||||
/* Undo the local locks */
|
||||
if( rc==SQLITE_OK ){
|
||||
p->exclMask &= ~mask;
|
||||
p->sharedMask &= ~mask;
|
||||
p->exclMask &= ~mask;
|
||||
}
|
||||
}
|
||||
}else if( flags & SQLITE_SHM_SHARED ){
|
||||
assert( n==1 );
|
||||
assert( (p->exclMask & (1<<ofst))==0 );
|
||||
if( (p->sharedMask & mask)==0 ){
|
||||
/* Case (b) - a shared lock. */
|
||||
|
||||
if( aLock[ofst]<0 ){
|
||||
/* An exclusive lock is held by some other connection. BUSY. */
|
||||
rc = SQLITE_BUSY;
|
||||
}else if( aLock[ofst]==0 ){
|
||||
rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
|
||||
@@ -5043,14 +5110,18 @@ static int unixShmLock(
|
||||
p->sharedMask |= mask;
|
||||
aLock[ofst]++;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* Case (c) - an exclusive lock. */
|
||||
int ii;
|
||||
|
||||
assert( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) );
|
||||
assert( (p->sharedMask & mask)==0 );
|
||||
assert( (p->exclMask & mask)==0 );
|
||||
|
||||
/* Make sure no sibling connections hold locks that will block this
|
||||
** lock. If any do, return SQLITE_BUSY right away. */
|
||||
int ii;
|
||||
for(ii=ofst; ii<ofst+n; ii++){
|
||||
assert( (p->sharedMask & mask)==0 );
|
||||
if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
|
||||
if( aLock[ii] ){
|
||||
rc = SQLITE_BUSY;
|
||||
break;
|
||||
}
|
||||
@@ -5061,7 +5132,6 @@ static int unixShmLock(
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( (p->sharedMask & mask)==0 );
|
||||
p->exclMask |= mask;
|
||||
for(ii=ofst; ii<ofst+n; ii++){
|
||||
aLock[ii] = -1;
|
||||
@@ -5069,8 +5139,19 @@ static int unixShmLock(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert( assertLockingArrayOk(pShmNode) );
|
||||
|
||||
/* Drop the mutexes acquired above. */
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
for(iMutex=ofst; iMutex<ofst+n; iMutex++){
|
||||
sqlite3_mutex_leave(pShmNode->aMutex[iMutex]);
|
||||
}
|
||||
#else
|
||||
sqlite3_mutex_leave(pShmNode->pShmMutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
|
||||
p->id, osGetpid(0), p->sharedMask, p->exclMask));
|
||||
return rc;
|
||||
|
||||
Reference in New Issue
Block a user