/ Check-in [6af2dca7]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Define an invariant to guarantee deadlock-free operation of SHM in os_unix.c and check that invariant with assert() statements.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | wal
Files: files | file ages | folders
SHA1: 6af2dca75b8139134ea394c1d71aefc6523f02e9
User & Date: drh 2010-05-01 17:57:36
Context
2010-05-03
08:04
Add the sqlite3_wal_checkpoint() and sqlite3_wal_autocheckpoint() APIs. check-in: 9803196d user: dan tags: wal
2010-05-01
18:23
Remove the xShmPush and xShmPull methods from the VFS. check-in: 69e07fdb user: drh tags: wal
17:57
Define an invariant to guarantee deadlock-free operation of SHM in os_unix.c and check that invariant with assert() statements. check-in: 6af2dca7 user: drh tags: wal
17:50
Rework mutexes on the SHM implemention for os_unix to avoid a deadlock during WAL recovery. check-in: 1a0f69be user: drh tags: wal
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

4585
4586
4587
4588
4589
4590
4591






4592
4593
4594
4595
4596
4597
4598
....
5142
5143
5144
5145
5146
5147
5148

5149
5150
5151
5152
5153
5154
5155
....
5180
5181
5182
5183
5184
5185
5186

5187
5188
5189
5190
5191
5192
5193
....
5242
5243
5244
5245
5246
5247
5248

5249
5250
5251
5252
5253
5254
5255
** 
**      fid
**      zFilename
**
** Either unixShmFile.mutex must be held or unixShmFile.nRef==0 and
** unixMutexHeld() is true when reading or writing any other field
** in this structure.






*/
struct unixShmFile {
  struct unixFileId fid;     /* Unique file identifier */
  sqlite3_mutex *mutex;      /* Mutex to access this object */
  sqlite3_mutex *mutexBuf;   /* Mutex to access zBuf[] */
  char *zFilename;           /* Name of the file */
  int h;                     /* Open file descriptor */
................................................................................
  void **ppBuf             /* Write mapping buffer origin here */
){
  unixShm *p = (unixShm*)pSharedMem;
  unixShmFile *pFile = p->pFile;
  int rc = SQLITE_OK;

  if( p->lockState!=SQLITE_SHM_CHECKPOINT && p->hasMutexBuf==0 ){

    sqlite3_mutex_enter(pFile->mutexBuf);
    p->hasMutexBuf = 1;
  }
  sqlite3_mutex_enter(pFile->mutex);
  if( pFile->szMap==0 || reqMapSize>pFile->szMap ){
    int actualSize;
    if( unixShmSize(pSharedMem, -1, &actualSize)==SQLITE_OK
................................................................................
** really want to release the lock, so in that case too, this routine
** is a no-op.
*/
static int unixShmRelease(sqlite3_shm *pSharedMem){
  unixShm *p = (unixShm*)pSharedMem;
  if( p->hasMutexBuf && p->lockState!=SQLITE_SHM_RECOVER ){
    unixShmFile *pFile = p->pFile;

    sqlite3_mutex_leave(pFile->mutexBuf);
    p->hasMutexBuf = 0;
  }
  return SQLITE_OK;
}

/*
................................................................................
    return SQLITE_OK;
  }

  OSTRACE(("SHM-LOCK shmid-%d, pid-%d request %s->%s\n",
            p->id, getpid(), azLkName[p->lockState], azLkName[desiredLock]));
  
  if( desiredLock==SQLITE_SHM_RECOVER && !p->hasMutexBuf ){

    sqlite3_mutex_enter(pFile->mutexBuf);
    p->hasMutexBuf = 1;
  }
  sqlite3_mutex_enter(pFile->mutex);
  switch( desiredLock ){
    case SQLITE_SHM_UNLOCK: {
      assert( p->lockState!=SQLITE_SHM_RECOVER );







>
>
>
>
>
>







 







>







 







>







 







>







4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
....
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
....
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
....
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
** 
**      fid
**      zFilename
**
** Either unixShmFile.mutex must be held or unixShmFile.nRef==0 and
** unixMutexHeld() is true when reading or writing any other field
** in this structure.
**
** To avoid deadlocks, mutex and mutexBuf are always released in the
** reverse order that they are acquired.  mutexBuf is always acquired
** first and released last.  This invariant is check by asserting
** sqlite3_mutex_notheld() on mutex whenever mutexBuf is acquired or
** released.
*/
struct unixShmFile {
  struct unixFileId fid;     /* Unique file identifier */
  sqlite3_mutex *mutex;      /* Mutex to access this object */
  sqlite3_mutex *mutexBuf;   /* Mutex to access zBuf[] */
  char *zFilename;           /* Name of the file */
  int h;                     /* Open file descriptor */
................................................................................
  void **ppBuf             /* Write mapping buffer origin here */
){
  unixShm *p = (unixShm*)pSharedMem;
  unixShmFile *pFile = p->pFile;
  int rc = SQLITE_OK;

  if( p->lockState!=SQLITE_SHM_CHECKPOINT && p->hasMutexBuf==0 ){
    assert( sqlite3_mutex_notheld(pFile->mutex) );
    sqlite3_mutex_enter(pFile->mutexBuf);
    p->hasMutexBuf = 1;
  }
  sqlite3_mutex_enter(pFile->mutex);
  if( pFile->szMap==0 || reqMapSize>pFile->szMap ){
    int actualSize;
    if( unixShmSize(pSharedMem, -1, &actualSize)==SQLITE_OK
................................................................................
** really want to release the lock, so in that case too, this routine
** is a no-op.
*/
static int unixShmRelease(sqlite3_shm *pSharedMem){
  unixShm *p = (unixShm*)pSharedMem;
  if( p->hasMutexBuf && p->lockState!=SQLITE_SHM_RECOVER ){
    unixShmFile *pFile = p->pFile;
    assert( sqlite3_mutex_notheld(pFile->mutex) );
    sqlite3_mutex_leave(pFile->mutexBuf);
    p->hasMutexBuf = 0;
  }
  return SQLITE_OK;
}

/*
................................................................................
    return SQLITE_OK;
  }

  OSTRACE(("SHM-LOCK shmid-%d, pid-%d request %s->%s\n",
            p->id, getpid(), azLkName[p->lockState], azLkName[desiredLock]));
  
  if( desiredLock==SQLITE_SHM_RECOVER && !p->hasMutexBuf ){
    assert( sqlite3_mutex_notheld(pFile->mutex) );
    sqlite3_mutex_enter(pFile->mutexBuf);
    p->hasMutexBuf = 1;
  }
  sqlite3_mutex_enter(pFile->mutex);
  switch( desiredLock ){
    case SQLITE_SHM_UNLOCK: {
      assert( p->lockState!=SQLITE_SHM_RECOVER );