aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/os_unix.c56
1 files changed, 42 insertions, 14 deletions
diff --git a/src/os_unix.c b/src/os_unix.c
index 634f5ee21..248309664 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -4698,7 +4698,7 @@ static const char *unixShmLockString(u8 mask){
** Locks block if the UNIX_SHM_MUTEX bit is set and are non-blocking
** otherwise.
*/
-static int unixShmSystemLocks(
+static int unixShmSystemLock(
unixShmFile *pFile, /* Apply locks to this open shared-memory segment */
int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */
u8 lockMask /* Which bytes to lock or unlock */
@@ -4709,6 +4709,9 @@ static int unixShmSystemLocks(
int rc; /* Result code form fcntl() */
u8 mask; /* Mask of bits in lockMask */
+ /* Access to the unixShmFile object is serialized by the caller */
+ assert( sqlite3_mutex_held(pFile->mutex) );
+
/* Initialize the locking parameters */
memset(&f, 0, sizeof(f));
f.l_type = lockType;
@@ -4787,6 +4790,9 @@ static int unixShmUnlock(
unixShm *pX; /* For looping over all sibling connections */
u8 allMask; /* Union of locks held by connections other than "p" */
+ /* Access to the unixShmFile object is serialized by the caller */
+ assert( sqlite3_mutex_held(pFile->mutex) );
+
/* We never try to unlock locks that we do not hold */
assert( ((p->exclMask|p->sharedMask) & unlockMask)==unlockMask );
@@ -4799,7 +4805,7 @@ static int unixShmUnlock(
/* Unlock the system-level locks */
if( (unlockMask & allMask)!=unlockMask ){
- rc = unixShmSystemLocks(pFile, F_UNLCK, unlockMask & ~allMask);
+ rc = unixShmSystemLock(pFile, F_UNLCK, unlockMask & ~allMask);
}else{
rc = SQLITE_OK;
}
@@ -4824,6 +4830,9 @@ static int unixShmSharedLock(
unixShm *pX; /* For looping over all sibling connections */
u8 allShared; /* Union of locks held by connections other than "p" */
+ /* Access to the unixShmFile object is serialized by the caller */
+ assert( sqlite3_mutex_held(pFile->mutex) );
+
/* Find out which shared locks are already held by sibling connections.
** If any sibling already holds an exclusive lock, go ahead and return
** SQLITE_BUSY.
@@ -4836,7 +4845,7 @@ static int unixShmSharedLock(
/* Get shared locks at the system level, if necessary */
if( (~allShared) & readMask ){
- rc = unixShmSystemLocks(pFile, F_RDLCK, readMask);
+ rc = unixShmSystemLock(pFile, F_RDLCK, readMask);
}else{
rc = SQLITE_OK;
}
@@ -4860,6 +4869,9 @@ static int unixShmExclusiveLock(
int rc; /* Result code */
unixShm *pX; /* For looping over all sibling connections */
+ /* Access to the unixShmFile object is serialized by the caller */
+ assert( sqlite3_mutex_held(pFile->mutex) );
+
/* Make sure no sibling connections hold locks that will block this
** lock. If any do, return SQLITE_BUSY right away.
*/
@@ -4872,7 +4884,7 @@ static int unixShmExclusiveLock(
/* Get the exclusive locks at the system level. Then if successful
** also mark the local connection as being locked.
*/
- rc = unixShmSystemLocks(pFile, F_WRLCK, writeMask);
+ rc = unixShmSystemLock(pFile, F_WRLCK, writeMask);
if( rc==SQLITE_OK ){
p->sharedMask &= ~writeMask;
p->exclMask |= writeMask;
@@ -4917,16 +4929,20 @@ static int unixShmOpen(
const char *zName, /* Name of file to mmap */
sqlite3_shm **pShm /* Write the unixShm object created here */
){
- struct unixShm *p = 0;
- struct unixShmFile *pFile = 0;
- int rc;
- struct unixFileId fid;
- struct stat sStat;
+ struct unixShm *p = 0; /* The connection to be opened */
+ struct unixShmFile *pFile = 0; /* The underlying mmapped file */
+ int rc; /* Result code */
+ struct unixFileId fid; /* Unix file identifier */
+ struct stat sStat; /* Result from stat() an fstat() */
+ /* Allocate space for the new sqlite3_shm object */
p = sqlite3_malloc( sizeof(*p) );
if( p==0 ) return SQLITE_NOMEM;
memset(p, 0, sizeof(*p));
+ /* Look to see if there is an existing unixShmFile that can be used.
+ ** If no matching unixShmFile currently exists, create a new one.
+ */
unixEnterMutex();
rc = stat(zName, &sStat);
if( rc==0 ){
@@ -4982,16 +4998,27 @@ static int unixShmOpen(
pFile->fid.ino = sStat.st_ino;
pFile->size = (int)sStat.st_size;
pFile->size = (pFile->size/SQLITE_UNIX_SHM_INCR)*SQLITE_UNIX_SHM_INCR;
- if( pFile->size==0 ){
- pFile->size = SQLITE_UNIX_SHM_INCR;
- rc = ftruncate(pFile->h, pFile->size);
- if( rc ){
- rc = SQLITE_FULL;
+
+ /* Check to see if another process is holding the dead-man switch.
+ ** If not, truncate the file to zero length.
+ */
+ if( unixShmSystemLock(pFile, F_WRLCK, UNIX_SHM_MUTEX) ){
+ rc = SQLITE_IOERR_LOCK;
+ goto shm_open_err;
+ }
+ if( unixShmSystemLock(pFile, F_WRLCK, UNIX_SHM_DMS)==SQLITE_OK ){
+ if( ftruncate(pFile->h, 0) ){
+ rc = SQLITE_IOERR;
goto shm_open_err;
}
+ pFile->size = 0;
}
+ rc = unixShmSystemLock(pFile, F_RDLCK, UNIX_SHM_DMS);
+ if( rc ) goto shm_open_err;
+ unixShmSystemLock(pFile, F_UNLCK, UNIX_SHM_MUTEX);
}
+ /* Make the new connection a child of the unixShmFile */
p->pFile = pFile;
p->pNext = pFile->pFirst;
#ifdef SQLITE_DEBUG
@@ -5003,6 +5030,7 @@ static int unixShmOpen(
unixLeaveMutex();
return SQLITE_OK;
+ /* Jump here on any error */
shm_open_err:
unixShmPurge();
sqlite3_free(p);