SQLite

Check-in [6af2dca75b]
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
Timelines: family | ancestors | descendants | both | wal
Files: files | file ages | folders
SHA1: 6af2dca75b8139134ea394c1d71aefc6523f02e9
User & Date: drh 2010-05-01 17:57:36.000
Context
2010-05-03
08:04
Add the sqlite3_wal_checkpoint() and sqlite3_wal_autocheckpoint() APIs. (check-in: 9803196dec user: dan tags: wal)
2010-05-01
18:23
Remove the xShmPush and xShmPull methods from the VFS. (check-in: 69e07fdbde 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: 6af2dca75b user: drh tags: wal)
17:50
Rework mutexes on the SHM implemention for os_unix to avoid a deadlock during WAL recovery. (check-in: 1a0f69bef2 user: drh tags: wal)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/os_unix.c.
4585
4586
4587
4588
4589
4590
4591






4592
4593
4594
4595
4596
4597
4598
** 
**      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 */







>
>
>
>
>
>







4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
** 
**      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 */
5142
5143
5144
5145
5146
5147
5148

5149
5150
5151
5152
5153
5154
5155
  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







>







5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
  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
5180
5181
5182
5183
5184
5185
5186

5187
5188
5189
5190
5191
5192
5193
** 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;
}

/*







>







5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
** 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;
}

/*
5242
5243
5244
5245
5246
5247
5248

5249
5250
5251
5252
5253
5254
5255
    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 );







>







5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
    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 );