/ Check-in [80481754]
Login

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

Overview
Comment:Experimental enhancements to mutex debugging.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | mutexDbg2
Files: files | file ages | folders
SHA1: 804817549cfecbe5e1c4cea605d54cb4164f9bb6
User & Date: mistachkin 2017-02-14 23:58:30
Context
2017-02-15
00:02
Compilation fix for POSIX. check-in: 9964ad24 user: mistachkin tags: mutexDbg2
2017-02-14
23:58
Experimental enhancements to mutex debugging. check-in: 80481754 user: mistachkin tags: mutexDbg2
21:47
Clarification of the help text for the command-line shell. check-in: ca4f1e49 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/mutex.c.

10
11
12
13
14
15
16





17
18
19
20
21
22
23
..
78
79
80
81
82
83
84









































85
86
87
88
89
90
91
**
*************************************************************************
** This file contains the C functions that implement mutexes.
**
** This file contains code that is common across all mutex implementations.
*/
#include "sqliteInt.h"






#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT)
/*
** For debugging purposes, record when the mutex subsystem is initialized
** and uninitialized so that we can assert() if there is an attempt to
** allocate a mutex while the system is uninitialized.
*/
................................................................................

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

  return rc;
}










































/*
** Retrieve a pointer to a static mutex or allocate a new dynamic one.
*/
sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
  if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;







>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
..
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
**
*************************************************************************
** This file contains the C functions that implement mutexes.
**
** This file contains code that is common across all mutex implementations.
*/
#include "sqliteInt.h"
#if SQLITE_OS_UNIX
#  include <pthread.h>
#elif SQLITE_OS_WIN
#  include "os_win.h"
#endif

#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT)
/*
** For debugging purposes, record when the mutex subsystem is initialized
** and uninitialized so that we can assert() if there is an attempt to
** allocate a mutex while the system is uninitialized.
*/
................................................................................

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

  return rc;
}

#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
/* Return a time value for use by the mutex subsystem. */
i64 sqlite3MutexTimeOfDay(void){
#ifdef SQLITE_GET_MUTEX_TIME
  return SQLITE_GET_MUTEX_TIME();
#else
  return 0;
#endif
}

/*
** Calculates the elapsed time, in milliseconds, that a particular mutex
** was held and issues a warning, via the sqlite3_log() interface, if it
** was held for "too long".
*/
void sqlite3MutexTimeAlert(
  sqlite3_mutex *p,
  i64 entered
){
  i64 exited = sqlite3MutexTimeOfDay();
  i64 elapsed;
  assert( p!=0 );
  assert( exited>=entered );
  elapsed = exited - entered;
  if( elapsed>SQLITE_MUTEX_ALERT_MILLISECONDS ){
    void *tid = 0;
    int mid = -1;
#ifdef SQLITE_GET_THREAD_ID
    tid = SQLITE_GET_THREAD_ID();
#endif
#ifdef SQLITE_GET_MUTEX_ID
    mid = SQLITE_GET_MUTEX_ID(p);
#endif
    sqlite3_log(SQLITE_NOTICE,
      "thread %p delayed %lldms for mutex %p (%d)",
      tid, elapsed, p, mid
    );
  }
}
#endif

/*
** Retrieve a pointer to a static mutex or allocate a new dynamic one.
*/
sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
  if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;

Changes to src/mutex_noop.c.

76
77
78
79
80
81
82



83
84
85
86
87
88
89
...
160
161
162
163
164
165
166



167
168
169
170
171



172
173
174
175
176
177
178
179
180
181
182
183



184
185
186
187
188
189
190

/*
** The mutex object
*/
typedef struct sqlite3_debug_mutex {
  int id;     /* The mutex type */
  int cnt;    /* Number of entries without a matching leave */



} sqlite3_debug_mutex;

/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
static int debugMutexHeld(sqlite3_mutex *pX){
................................................................................
** can enter.  If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
static void debugMutexEnter(sqlite3_mutex *pX){
  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
  assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
  p->cnt++;



}
static int debugMutexTry(sqlite3_mutex *pX){
  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
  assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
  p->cnt++;



  return SQLITE_OK;
}

/*
** The sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread.  The behavior
** is undefined if the mutex is not currently entered or
** is not currently allocated.  SQLite will never do either.
*/
static void debugMutexLeave(sqlite3_mutex *pX){
  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
  assert( debugMutexHeld(pX) );



  p->cnt--;
  assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
}

sqlite3_mutex_methods const *sqlite3NoopMutex(void){
  static const sqlite3_mutex_methods sMutex = {
    debugMutexInit,







>
>
>







 







>
>
>





>
>
>












>
>
>







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

/*
** The mutex object
*/
typedef struct sqlite3_debug_mutex {
  int id;     /* The mutex type */
  int cnt;    /* Number of entries without a matching leave */
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
  i64 entered; /* Time that mutex was entered */
#endif
} sqlite3_debug_mutex;

/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
static int debugMutexHeld(sqlite3_mutex *pX){
................................................................................
** can enter.  If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
static void debugMutexEnter(sqlite3_mutex *pX){
  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
  assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
  p->cnt++;
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
  p->entered = sqlite3MutexTimeOfDay();
#endif
}
static int debugMutexTry(sqlite3_mutex *pX){
  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
  assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
  p->cnt++;
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
  p->entered = sqlite3MutexTimeOfDay();
#endif
  return SQLITE_OK;
}

/*
** The sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread.  The behavior
** is undefined if the mutex is not currently entered or
** is not currently allocated.  SQLite will never do either.
*/
static void debugMutexLeave(sqlite3_mutex *pX){
  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
  assert( debugMutexHeld(pX) );
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
  sqlite3MutexTimeAlert((sqlite3_mutex*)p, p->entered);
#endif
  p->cnt--;
  assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
}

sqlite3_mutex_methods const *sqlite3NoopMutex(void){
  static const sqlite3_mutex_methods sMutex = {
    debugMutexInit,

Changes to src/mutex_unix.c.

39
40
41
42
43
44
45



46
47
48
49
50
51
52
...
257
258
259
260
261
262
263



264
265
266
267
268
269
270
271
272



273
274
275
276
277
278
279
...
300
301
302
303
304
305
306



307
308
309
310
311
312
313
314
315
316
317
318



319
320
321
322
323
324
325
...
346
347
348
349
350
351
352



353
354
355



356
357
358
359
360
361
362
** Each recursive mutex is an instance of the following structure.
*/
struct sqlite3_mutex {
  pthread_mutex_t mutex;     /* Mutex controlling the lock */
#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
  int id;                    /* Mutex type */
#endif



#if SQLITE_MUTEX_NREF
  volatile int nRef;         /* Number of entrances */
  volatile pthread_t owner;  /* Thread that is within this mutex */
  int trace;                 /* True to trace changes */
#endif
};
#if SQLITE_MUTEX_NREF
................................................................................
  */
  {
    pthread_t self = pthread_self();
    if( p->nRef>0 && pthread_equal(p->owner, self) ){
      p->nRef++;
    }else{
      pthread_mutex_lock(&p->mutex);



      assert( p->nRef==0 );
      p->owner = self;
      p->nRef = 1;
    }
  }
#else
  /* Use the built-in recursive mutexes if they are available.
  */
  pthread_mutex_lock(&p->mutex);



#if SQLITE_MUTEX_NREF
  assert( p->nRef>0 || p->owner==0 );
  p->owner = pthread_self();
  p->nRef++;
#endif
#endif

................................................................................
  */
  {
    pthread_t self = pthread_self();
    if( p->nRef>0 && pthread_equal(p->owner, self) ){
      p->nRef++;
      rc = SQLITE_OK;
    }else if( pthread_mutex_trylock(&p->mutex)==0 ){



      assert( p->nRef==0 );
      p->owner = self;
      p->nRef = 1;
      rc = SQLITE_OK;
    }else{
      rc = SQLITE_BUSY;
    }
  }
#else
  /* Use the built-in recursive mutexes if they are available.
  */
  if( pthread_mutex_trylock(&p->mutex)==0 ){



#if SQLITE_MUTEX_NREF
    p->owner = pthread_self();
    p->nRef++;
#endif
    rc = SQLITE_OK;
  }else{
    rc = SQLITE_BUSY;
................................................................................
  p->nRef--;
  if( p->nRef==0 ) p->owner = 0;
#endif
  assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );

#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
  if( p->nRef==0 ){



    pthread_mutex_unlock(&p->mutex);
  }
#else



  pthread_mutex_unlock(&p->mutex);
#endif

#ifdef SQLITE_DEBUG
  if( p->trace ){
    printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
  }







>
>
>







 







>
>
>









>
>
>







 







>
>
>












>
>
>







 







>
>
>



>
>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
** Each recursive mutex is an instance of the following structure.
*/
struct sqlite3_mutex {
  pthread_mutex_t mutex;     /* Mutex controlling the lock */
#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
  int id;                    /* Mutex type */
#endif
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
  i64 entered;               /* Time that mutex was entered */
#endif
#if SQLITE_MUTEX_NREF
  volatile int nRef;         /* Number of entrances */
  volatile pthread_t owner;  /* Thread that is within this mutex */
  int trace;                 /* True to trace changes */
#endif
};
#if SQLITE_MUTEX_NREF
................................................................................
  */
  {
    pthread_t self = pthread_self();
    if( p->nRef>0 && pthread_equal(p->owner, self) ){
      p->nRef++;
    }else{
      pthread_mutex_lock(&p->mutex);
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
      p->entered = sqlite3MutexTimeOfDay();
#endif
      assert( p->nRef==0 );
      p->owner = self;
      p->nRef = 1;
    }
  }
#else
  /* Use the built-in recursive mutexes if they are available.
  */
  pthread_mutex_lock(&p->mutex);
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
  p->entered = sqlite3MutexTimeOfDay();
#endif
#if SQLITE_MUTEX_NREF
  assert( p->nRef>0 || p->owner==0 );
  p->owner = pthread_self();
  p->nRef++;
#endif
#endif

................................................................................
  */
  {
    pthread_t self = pthread_self();
    if( p->nRef>0 && pthread_equal(p->owner, self) ){
      p->nRef++;
      rc = SQLITE_OK;
    }else if( pthread_mutex_trylock(&p->mutex)==0 ){
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
      p->entered = sqlite3MutexTimeOfDay();
#endif
      assert( p->nRef==0 );
      p->owner = self;
      p->nRef = 1;
      rc = SQLITE_OK;
    }else{
      rc = SQLITE_BUSY;
    }
  }
#else
  /* Use the built-in recursive mutexes if they are available.
  */
  if( pthread_mutex_trylock(&p->mutex)==0 ){
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
    p->entered = sqlite3MutexTimeOfDay();
#endif
#if SQLITE_MUTEX_NREF
    p->owner = pthread_self();
    p->nRef++;
#endif
    rc = SQLITE_OK;
  }else{
    rc = SQLITE_BUSY;
................................................................................
  p->nRef--;
  if( p->nRef==0 ) p->owner = 0;
#endif
  assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );

#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
  if( p->nRef==0 ){
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
    sqlite3MutexTimeAlert(p, p->entered);
#endif
    pthread_mutex_unlock(&p->mutex);
  }
#else
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
  sqlite3MutexTimeAlert(p, p->entered);
#endif
  pthread_mutex_unlock(&p->mutex);
#endif

#ifdef SQLITE_DEBUG
  if( p->trace ){
    printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
  }

Changes to src/mutex_w32.c.

33
34
35
36
37
38
39



40
41
42
43
44
45
46
...
289
290
291
292
293
294
295



296
297
298
299
300
301
302
...
326
327
328
329
330
331
332



333
334
335
336
337
338
339
...
363
364
365
366
367
368
369



370
371
372
373
374
375
376

/*
** Each recursive mutex is an instance of the following structure.
*/
struct sqlite3_mutex {
  CRITICAL_SECTION mutex;    /* Mutex controlling the lock */
  int id;                    /* Mutex type */



#ifdef SQLITE_DEBUG
  volatile int nRef;         /* Number of enterances */
  volatile DWORD owner;      /* Thread holding this mutex */
  volatile int trace;        /* True to trace changes */
#endif
};

................................................................................
  assert( p );
  assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
#else
  assert( p );
#endif
  assert( winMutex_isInit==1 );
  EnterCriticalSection(&p->mutex);



#ifdef SQLITE_DEBUG
  assert( p->nRef>0 || p->owner==0 );
  p->owner = tid;
  p->nRef++;
  if( p->trace ){
    OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
             tid, p, p->trace, p->nRef));
................................................................................
  assert( winMutex_isInit==1 );
  assert( winMutex_isNt>=-1 && winMutex_isNt<=1 );
  if( winMutex_isNt<0 ){
    winMutex_isNt = sqlite3_win32_is_nt();
  }
  assert( winMutex_isNt==0 || winMutex_isNt==1 );
  if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){



#ifdef SQLITE_DEBUG
    p->owner = tid;
    p->nRef++;
#endif
    rc = SQLITE_OK;
  }
#else
................................................................................
  assert( p->nRef>0 );
  assert( p->owner==tid );
  p->nRef--;
  if( p->nRef==0 ) p->owner = 0;
  assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
#endif
  assert( winMutex_isInit==1 );



  LeaveCriticalSection(&p->mutex);
#ifdef SQLITE_DEBUG
  if( p->trace ){
    OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
             tid, p, p->trace, p->nRef));
  }
#endif







>
>
>







 







>
>
>







 







>
>
>







 







>
>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388

/*
** Each recursive mutex is an instance of the following structure.
*/
struct sqlite3_mutex {
  CRITICAL_SECTION mutex;    /* Mutex controlling the lock */
  int id;                    /* Mutex type */
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
  i64 entered;               /* Time that mutex was entered */
#endif
#ifdef SQLITE_DEBUG
  volatile int nRef;         /* Number of enterances */
  volatile DWORD owner;      /* Thread holding this mutex */
  volatile int trace;        /* True to trace changes */
#endif
};

................................................................................
  assert( p );
  assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
#else
  assert( p );
#endif
  assert( winMutex_isInit==1 );
  EnterCriticalSection(&p->mutex);
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
  p->entered = sqlite3MutexTimeOfDay();
#endif
#ifdef SQLITE_DEBUG
  assert( p->nRef>0 || p->owner==0 );
  p->owner = tid;
  p->nRef++;
  if( p->trace ){
    OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
             tid, p, p->trace, p->nRef));
................................................................................
  assert( winMutex_isInit==1 );
  assert( winMutex_isNt>=-1 && winMutex_isNt<=1 );
  if( winMutex_isNt<0 ){
    winMutex_isNt = sqlite3_win32_is_nt();
  }
  assert( winMutex_isNt==0 || winMutex_isNt==1 );
  if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
    p->entered = sqlite3MutexTimeOfDay();
#endif
#ifdef SQLITE_DEBUG
    p->owner = tid;
    p->nRef++;
#endif
    rc = SQLITE_OK;
  }
#else
................................................................................
  assert( p->nRef>0 );
  assert( p->owner==tid );
  p->nRef--;
  if( p->nRef==0 ) p->owner = 0;
  assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
#endif
  assert( winMutex_isInit==1 );
#if SQLITE_MUTEX_ALERT_MILLISECONDS>0
  sqlite3MutexTimeAlert(p, p->entered);
#endif
  LeaveCriticalSection(&p->mutex);
#ifdef SQLITE_DEBUG
  if( p->trace ){
    OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
             tid, p, p->trace, p->nRef));
  }
#endif

Changes to src/sqliteInt.h.

3522
3523
3524
3525
3526
3527
3528





































































3529
3530
3531
3532
3533
3534
3535
#endif
#if !defined(SQLITE_MUTEX_OMIT) && !defined(SQLITE_MUTEX_NOOP)
  void sqlite3MemoryBarrier(void);
#else
# define sqlite3MemoryBarrier()
#endif






































































sqlite3_int64 sqlite3StatusValue(int);
void sqlite3StatusUp(int, int);
void sqlite3StatusDown(int, int);
void sqlite3StatusHighwater(int, int);

/* Access to mutexes used by sqlite3_status() */
sqlite3_mutex *sqlite3Pcache1Mutex(void);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
#endif
#if !defined(SQLITE_MUTEX_OMIT) && !defined(SQLITE_MUTEX_NOOP)
  void sqlite3MemoryBarrier(void);
#else
# define sqlite3MemoryBarrier()
#endif

/*
** When SQLITE_MUTEX_ALERT_MILLISECONDS is greater than zero, extra code
** will be included to issue warnings via the sqlite3_log() interface if
** a mutex is held for longer than the number of milliseconds specified
** by SQLITE_MUTEX_ALERT_MILLISECONDS.
*/
#ifndef SQLITE_MUTEX_ALERT_MILLISECONDS
# define SQLITE_MUTEX_ALERT_MILLISECONDS (0)
#endif

#if !defined(SQLITE_MUTEX_OMIT) && SQLITE_MUTEX_ALERT_MILLISECONDS>0
  i64 sqlite3MutexTimeOfDay(void);
  void sqlite3MutexTimeAlert(sqlite3_mutex *, i64);

/*
** This macro returns a 64-bit integer time value, in milliseconds,
** or zero if that information is not available.
*/
# ifndef SQLITE_GET_MUTEX_TIME
#  if SQLITE_OS_UNIX
#   define SQLITE_GET_MUTEX_TIME()   (((i64)time())*1000)
#  elif SQLITE_OS_WIN
#   define SQLITE_GET_MUTEX_TIME()   ((i64)GetTickCount())
#  else
#   define SQLITE_GET_MUTEX_TIME()   (0)
#  endif
# endif

/*
** This macro returns the integer type for the specified mutex or
** negative one if that information is not available.
*/
# ifndef SQLITE_GET_MUTEX_ID
#  if SQLITE_OS_UNIX
#   if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
#    define SQLITE_GET_MUTEX_ID(p)    \
         *((int*)(((unsigned char*)(p))+sizeof(pthread_mutex_t)))
#   else
#    define SQLITE_GET_MUTEX_ID(p)    (-1)
#   endif
#  elif SQLITE_OS_WIN
#   define SQLITE_GET_MUTEX_ID(p)     \
         *((int*)(((unsigned char*)(p))+sizeof(CRITICAL_SECTION)))
#  else
#   define SQLITE_GET_MUTEX_ID(p)     (-1)
#  endif
# endif

/*
** This macro returns the integer identifier for the current thread
** or zero if that information is not available.
*/
# ifndef SQLITE_GET_THREAD_ID
#  if SQLITE_OS_UNIX
#   define SQLITE_GET_THREAD_ID()     ((void *)pthread_self())
#  elif SQLITE_OS_WIN
#   define SQLITE_GET_THREAD_ID()     ((void *)GetCurrentThreadId())
#  else
#   define SQLITE_GET_THREAD_ID()     ((void *)0)
#  endif
# endif
#else
# define sqlite3MutexTimeOfDay()      (0)
# define sqlite3MutexTimeAlert(X,Y)
# define SQLITE_GET_MUTEX_TIME()      (0)
# define SQLITE_GET_MUTEX_ID(p)       (-1)
# define SQLITE_GET_THREAD_ID()       ((void *)0)
#endif

sqlite3_int64 sqlite3StatusValue(int);
void sqlite3StatusUp(int, int);
void sqlite3StatusDown(int, int);
void sqlite3StatusHighwater(int, int);

/* Access to mutexes used by sqlite3_status() */
sqlite3_mutex *sqlite3Pcache1Mutex(void);