/ Check-in [da0587c5]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Simplify thread-safety of mutex initialization.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | mutexInitSimpleCmpSwap
Files: files | file ages | folders
SHA1: da0587c522163833e5e542f7722aeb69b3183ac1
User & Date: mistachkin 2015-09-23 16:24:19
Context
2015-09-23
16:33
Correct superfluous whitespace difference. No functional changes. check-in: 8d69983d user: mistachkin tags: mutexInitSimpleCmpSwap
16:24
Simplify thread-safety of mutex initialization. check-in: da0587c5 user: mistachkin tags: mutexInitSimpleCmpSwap
15:54
Merge updates from trunk. Closed-Leaf check-in: 6b85f8cd user: mistachkin tags: mutexInitCmpSwap
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/global.c.

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
   SQLITE_USE_URI,            /* bOpenUri */
   SQLITE_ALLOW_COVERING_INDEX_SCAN,   /* bUseCis */
   0x7ffffffe,                /* mxStrlen */
   0,                         /* neverCorrupt */
   128,                       /* szLookaside */
   500,                       /* nLookaside */
   {0,0,0,0,0,0,0,0},         /* m */
   (void*)0,                  /* pMutex */
   {0,0,0,0,0,0,0,0,0},       /* mutex */
   {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
   (void*)0,                  /* pHeap */
   0,                         /* nHeap */
   0, 0,                      /* mnHeap, mxHeap */
   SQLITE_DEFAULT_MMAP_SIZE,  /* szMmap */
   SQLITE_MAX_MMAP_SIZE,      /* mxMmap */







<







170
171
172
173
174
175
176

177
178
179
180
181
182
183
   SQLITE_USE_URI,            /* bOpenUri */
   SQLITE_ALLOW_COVERING_INDEX_SCAN,   /* bUseCis */
   0x7ffffffe,                /* mxStrlen */
   0,                         /* neverCorrupt */
   128,                       /* szLookaside */
   500,                       /* nLookaside */
   {0,0,0,0,0,0,0,0},         /* m */

   {0,0,0,0,0,0,0,0,0},       /* mutex */
   {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
   (void*)0,                  /* pHeap */
   0,                         /* nHeap */
   0, 0,                      /* mnHeap, mxHeap */
   SQLITE_DEFAULT_MMAP_SIZE,  /* szMmap */
   SQLITE_MAX_MMAP_SIZE,      /* mxMmap */

Changes to src/main.c.

167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
...
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412

413
414
415
416
417
418

419

420
421
422
423
424
425
426
  ** This operation is protected by the STATIC_MASTER mutex.  Note that
  ** MutexAlloc() is called for a static mutex prior to initializing the
  ** malloc subsystem - this implies that the allocation of a static
  ** mutex must not require support from the malloc subsystem.
  */
  MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
  sqlite3_mutex_enter(pMaster);
  if( sqlite3GlobalConfig.isInit ){
    assert( sqlite3GlobalConfig.isMutexInit );
    assert( sqlite3GlobalConfig.isMallocInit );
    sqlite3_mutex_leave(pMaster);
    return SQLITE_OK;
  }
  sqlite3GlobalConfig.isMutexInit = 1; /* possibly redundant */
  if( !sqlite3GlobalConfig.isMallocInit ){
    rc = sqlite3MallocInit();
  }
  if( rc==SQLITE_OK ){
    sqlite3GlobalConfig.isMallocInit = 1;
    if( !sqlite3GlobalConfig.pInitMutex ){
      sqlite3GlobalConfig.pInitMutex =
................................................................................
#endif
  }
  if( sqlite3GlobalConfig.isMutexInit ){
    sqlite3MutexEnd();
    sqlite3GlobalConfig.isMutexInit = 0;
  }

  /*
  ** Force the state of the mutex subsystem to be completely reset now, even
  ** if the configured xMutexEnd(), if any, failed.  This is not thread-safe.
  ** This is necessary even if the xMutexInit() was never called, due to the
  ** possiblity of this state being changed via SQLITE_CONFIG_MUTEX.  After
  ** this point, the application must enable any custom mutex implementation
  ** again via SQLITE_CONFIG_MUTEX, if necessary.
  */
  sqlite3GlobalConfig.pMutex = 0;
  memset(&sqlite3GlobalConfig.mutex, 0, sizeof(sqlite3_mutex_methods));

  return SQLITE_OK;
}

/*
** This API allows applications to modify the global configuration of
** the SQLite library at run-time.
**
................................................................................
      sqlite3GlobalConfig.bCoreMutex = 1;  /* Enable mutex on core */
      sqlite3GlobalConfig.bFullMutex = 1;  /* Enable mutex on connections */
      break;
    }
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */
    case SQLITE_CONFIG_MUTEX: {
      /* Atomically compare-and-swap the mutex implementation pointer to
       * help prevent a race condition with sqlite3MutexInit(). */
      if( sqlite3CompareAndSwap((void * volatile *)&sqlite3GlobalConfig.pMutex,
                                0, &sqlite3GlobalConfig.mutex)==0 ){
        /* Specify an alternative mutex implementation */
        sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*);
      }else{
        rc = SQLITE_ERROR;
      }

      break;
    }
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */
    case SQLITE_CONFIG_GETMUTEX: {
      /* Retrieve the current mutex implementation */

      *va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex;

      break;
    }
#endif

    case SQLITE_CONFIG_MALLOC: {
      /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a
      ** single argument which is a pointer to an instance of the







<
|
<
<
<
<
<







 







<
<
<
<
<
<
<
<
<
<
<







 







|
<
<
|
<
|
<
<
<
>






>
|
>







167
168
169
170
171
172
173

174





175
176
177
178
179
180
181
...
325
326
327
328
329
330
331











332
333
334
335
336
337
338
...
380
381
382
383
384
385
386
387


388

389



390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
  ** This operation is protected by the STATIC_MASTER mutex.  Note that
  ** MutexAlloc() is called for a static mutex prior to initializing the
  ** malloc subsystem - this implies that the allocation of a static
  ** mutex must not require support from the malloc subsystem.
  */
  MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
  sqlite3_mutex_enter(pMaster);

  sqlite3GlobalConfig.isMutexInit = 1;





  if( !sqlite3GlobalConfig.isMallocInit ){
    rc = sqlite3MallocInit();
  }
  if( rc==SQLITE_OK ){
    sqlite3GlobalConfig.isMallocInit = 1;
    if( !sqlite3GlobalConfig.pInitMutex ){
      sqlite3GlobalConfig.pInitMutex =
................................................................................
#endif
  }
  if( sqlite3GlobalConfig.isMutexInit ){
    sqlite3MutexEnd();
    sqlite3GlobalConfig.isMutexInit = 0;
  }












  return SQLITE_OK;
}

/*
** This API allows applications to modify the global configuration of
** the SQLite library at run-time.
**
................................................................................
      sqlite3GlobalConfig.bCoreMutex = 1;  /* Enable mutex on core */
      sqlite3GlobalConfig.bFullMutex = 1;  /* Enable mutex on connections */
      break;
    }
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */
    case SQLITE_CONFIG_MUTEX: {
      /* Specify an alternative mutex implementation */


      sqlite3MutexCopy(&sqlite3GlobalConfig.mutex,

                       va_arg(ap, sqlite3_mutex_methods*));



      sqlite3MemoryBarrier();
      break;
    }
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */
    case SQLITE_CONFIG_GETMUTEX: {
      /* Retrieve the current mutex implementation */
      sqlite3MemoryBarrier();
      sqlite3MutexCopy(va_arg(ap, sqlite3_mutex_methods*),
                       &sqlite3GlobalConfig.mutex);
      break;
    }
#endif

    case SQLITE_CONFIG_MALLOC: {
      /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a
      ** single argument which is a pointer to an instance of the

Changes to src/mutex.c.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
..
71
72
73
74
75
76
77
78
79



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
** allocate a mutex while the system is uninitialized.
*/
static SQLITE_WSD int mutexIsInit = 0;
#endif /* SQLITE_DEBUG && !defined(SQLITE_MUTEX_OMIT) */


#ifndef SQLITE_MUTEX_OMIT
/*
** This structure is for use by mutexIsInvalid() only.  It represents an
** invalid mutex implementation (i.e. one where all the function pointers
** are null).
*/
static const sqlite3_mutex_methods mutexNullMethods = {
  0, /* xMutexInit */
  0, /* xMutexEnd */
  0, /* xMutexAlloc */
  0, /* xMutexFree */
  0, /* xMutexEnter */
  0, /* xMutexTry */
  0, /* xMutexLeave */
  0, /* xMutexHeld */
  0  /* xMutexNotheld */
};

/*
** Returns non-zero if the currently configured mutex implemention is
** invalid (i.e. all of its function pointers are null).
*/
static int mutexIsInvalid(void){
  return memcmp(&sqlite3GlobalConfig.mutex, &mutexNullMethods,
                sizeof(sqlite3_mutex_methods))==0;
}

/*
** Copies a mutex implementation.  Both arguments must point to valid
** memory.
*/
static void mutexCopy(
  sqlite3_mutex_methods *pTo,
  sqlite3_mutex_methods const *pFrom
){
  pTo->xMutexInit = pFrom->xMutexInit;
  pTo->xMutexEnd = pFrom->xMutexEnd;
  pTo->xMutexFree = pFrom->xMutexFree;
  pTo->xMutexEnter = pFrom->xMutexEnter;
................................................................................
  pTo->xMutexAlloc = pFrom->xMutexAlloc;
}

/*
** Initialize the mutex system.
*/
int sqlite3MutexInit(void){ 
  static int initPending = 0;
  int rc;



  if( sqlite3CompareAndSwap((void * volatile *)&sqlite3GlobalConfig.pMutex,
                   0, &sqlite3GlobalConfig.mutex)==0 || mutexIsInvalid() ){
    /* If the mutex implementation pointer has not been set, then the user
    ** did not install a mutex implementation via sqlite3_config() prior to
    ** sqlite3_initialize() being called.  This block copies the pointers
    ** for the default implementation into the sqlite3GlobalConfig structure.
    */
    sqlite3_mutex_methods const *pFrom;

    if( sqlite3GlobalConfig.bCoreMutex ){
      pFrom = sqlite3DefaultMutex();
    }else{
      pFrom = sqlite3NoopMutex();
    }
    mutexCopy(&sqlite3GlobalConfig.mutex, pFrom);
    sqlite3MemoryBarrier();
  }
  if( !initPending ){
    assert( sqlite3GlobalConfig.mutex.xMutexInit );
    initPending = 1;
    rc = sqlite3GlobalConfig.mutex.xMutexInit();
    initPending = 0;
  }

#ifdef SQLITE_DEBUG
  GLOBAL(int, mutexIsInit) = 1;
#endif

  return rc;
}







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




|







 







<

>
>
>
|
|
|
|
|
|


<





|


<
|
<
|
<
<







22
23
24
25
26
27
28


























29
30
31
32
33
34
35
36
37
38
39
40
..
45
46
47
48
49
50
51

52
53
54
55
56
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71

72

73


74
75
76
77
78
79
80
** allocate a mutex while the system is uninitialized.
*/
static SQLITE_WSD int mutexIsInit = 0;
#endif /* SQLITE_DEBUG && !defined(SQLITE_MUTEX_OMIT) */


#ifndef SQLITE_MUTEX_OMIT


























/*
** Copies a mutex implementation.  Both arguments must point to valid
** memory.
*/
void sqlite3MutexCopy(
  sqlite3_mutex_methods *pTo,
  sqlite3_mutex_methods const *pFrom
){
  pTo->xMutexInit = pFrom->xMutexInit;
  pTo->xMutexEnd = pFrom->xMutexEnd;
  pTo->xMutexFree = pFrom->xMutexFree;
  pTo->xMutexEnter = pFrom->xMutexEnter;
................................................................................
  pTo->xMutexAlloc = pFrom->xMutexAlloc;
}

/*
** Initialize the mutex system.
*/
int sqlite3MutexInit(void){ 

  int rc;

  sqlite3MemoryBarrier();
  if( sqlite3CompareAndSwap(
                   (void * volatile *)&sqlite3GlobalConfig.mutex.xMutexAlloc,
                   0, sqlite3GlobalConfig.mutex.xMutexAlloc)==0 ){
    /* If the xMutexAlloc method has not been set, then the user did not
    ** install a mutex implementation via sqlite3_config() prior to 
    ** sqlite3_initialize() being called. This block copies pointers to
    ** the default implementation into the sqlite3GlobalConfig structure.
    */
    sqlite3_mutex_methods const *pFrom;

    if( sqlite3GlobalConfig.bCoreMutex ){
      pFrom = sqlite3DefaultMutex();
    }else{
      pFrom = sqlite3NoopMutex();
    }
    sqlite3MutexCopy(&sqlite3GlobalConfig.mutex, pFrom);
    sqlite3MemoryBarrier();
  }

  assert( sqlite3GlobalConfig.mutex.xMutexInit );

  rc = sqlite3GlobalConfig.mutex.xMutexInit();



#ifdef SQLITE_DEBUG
  GLOBAL(int, mutexIsInit) = 1;
#endif

  return rc;
}

Changes to src/sqliteInt.h.

2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
....
3192
3193
3194
3195
3196
3197
3198

3199
3200

3201
3202
3203
3204
3205
3206
3207
  int bOpenUri;                     /* True to interpret filenames as URIs */
  int bUseCis;                      /* Use covering indices for full-scans */
  int mxStrlen;                     /* Maximum string length */
  int neverCorrupt;                 /* Database is always well-formed */
  int szLookaside;                  /* Default lookaside buffer size */
  int nLookaside;                   /* Default lookaside buffer count */
  sqlite3_mem_methods m;            /* Low-level memory allocation interface */
  sqlite3_mutex_methods *pMutex;    /* Address of mutex member or zero. */
  sqlite3_mutex_methods mutex;      /* Low-level mutex interface */
  sqlite3_pcache_methods2 pcache2;  /* Low-level page-cache interface */
  void *pHeap;                      /* Heap storage space */
  int nHeap;                        /* Size of pHeap[] */
  int mnReq, mxReq;                 /* Min and max heap requests sizes */
  sqlite3_int64 szMmap;             /* mmap() space per open file */
  sqlite3_int64 mxMmap;             /* Maximum value for szMmap */
................................................................................
  sqlite3_mutex_methods const *sqlite3NoopMutex(void);
  void *sqlite3NoopCompareAndSwap(void * volatile *, void *, void *);
  sqlite3_mutex *sqlite3MutexAlloc(int);
  int sqlite3MutexInit(void);
  int sqlite3MutexEnd(void);
#endif
#if !defined(SQLITE_MUTEX_OMIT) && !defined(SQLITE_MUTEX_NOOP)

  void sqlite3MemoryBarrier(void);
#else

# define sqlite3MemoryBarrier()
#endif
#if !defined(SQLITE_MUTEX_OMIT)
# if !defined(SQLITE_MUTEX_NOOP)
   void *sqlite3CompareAndSwap(void * volatile *, void *, void *);
# else
#  define sqlite3CompareAndSwap sqlite3NoopCompareAndSwap







<







 







>


>







2934
2935
2936
2937
2938
2939
2940

2941
2942
2943
2944
2945
2946
2947
....
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
  int bOpenUri;                     /* True to interpret filenames as URIs */
  int bUseCis;                      /* Use covering indices for full-scans */
  int mxStrlen;                     /* Maximum string length */
  int neverCorrupt;                 /* Database is always well-formed */
  int szLookaside;                  /* Default lookaside buffer size */
  int nLookaside;                   /* Default lookaside buffer count */
  sqlite3_mem_methods m;            /* Low-level memory allocation interface */

  sqlite3_mutex_methods mutex;      /* Low-level mutex interface */
  sqlite3_pcache_methods2 pcache2;  /* Low-level page-cache interface */
  void *pHeap;                      /* Heap storage space */
  int nHeap;                        /* Size of pHeap[] */
  int mnReq, mxReq;                 /* Min and max heap requests sizes */
  sqlite3_int64 szMmap;             /* mmap() space per open file */
  sqlite3_int64 mxMmap;             /* Maximum value for szMmap */
................................................................................
  sqlite3_mutex_methods const *sqlite3NoopMutex(void);
  void *sqlite3NoopCompareAndSwap(void * volatile *, void *, void *);
  sqlite3_mutex *sqlite3MutexAlloc(int);
  int sqlite3MutexInit(void);
  int sqlite3MutexEnd(void);
#endif
#if !defined(SQLITE_MUTEX_OMIT) && !defined(SQLITE_MUTEX_NOOP)
  void sqlite3MutexCopy(sqlite3_mutex_methods *, sqlite3_mutex_methods const *);
  void sqlite3MemoryBarrier(void);
#else
# define sqlite3MutexCopy(x,y)
# define sqlite3MemoryBarrier()
#endif
#if !defined(SQLITE_MUTEX_OMIT)
# if !defined(SQLITE_MUTEX_NOOP)
   void *sqlite3CompareAndSwap(void * volatile *, void *, void *);
# else
#  define sqlite3CompareAndSwap sqlite3NoopCompareAndSwap