/ Check-in [1025873f]
Login

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

Overview
Comment:Enhance mutex testing to include APP and VFS static mutexes.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1025873fdfd9e7e53094c48af1a79c60ae50ae97
User & Date: mistachkin 2015-07-03 23:11:36
References
2015-07-03
23:29
Correction to check-in [1025873fdf], tighten up the number of static test mutexes. check-in: 4e515897 user: mistachkin tags: trunk
Context
2015-07-03
23:12
Update clean target in MSVC makefile. check-in: e6c03e72 user: mistachkin tags: trunk
23:11
Enhance mutex testing to include APP and VFS static mutexes. check-in: 1025873f user: mistachkin tags: trunk
21:38
Add static mutexes for use by the built-in / third-party VFSs and use the built-in VFS mutex where appropriate. check-in: b202e2a1 user: mistachkin tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/test_mutex.c.

15
16
17
18
19
20
21


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
..
74
75
76
77
78
79
80
81

82
83
84
85
86
87
88



89
90
91
92
93
94
95
96
...
106
107
108
109
110
111
112


113
114
115
116
117
118
119
120
121


122
123
124
125
126
127
128
...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
...
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
...
366
367
368
369
370
371
372


















































373
374
375
376
377
378
379
...
413
414
415
416
417
418
419



420
421
422
423
424
425
426
#include "tcl.h"
#include "sqlite3.h"
#include "sqliteInt.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>



/* defined in main.c */
extern const char *sqlite3ErrName(int);








/* A countable mutex */
struct sqlite3_mutex {
  sqlite3_mutex *pReal;
  int eType;
};

/* State variables */
static struct test_mutex_globals {
  int isInstalled;              /* True if installed */
  int disableInit;              /* True to cause sqlite3_initalize() to fail */
  int disableTry;               /* True to force sqlite3_mutex_try() to fail */
  int isInit;                   /* True if initialized */
  sqlite3_mutex_methods m;      /* Interface to "real" mutex system */
  int aCounter[8];              /* Number of grabs of each type of mutex */
  sqlite3_mutex aStatic[6];     /* The six static mutexes */
} g = {0};

/* Return true if the countable mutex is currently held */
static int counterMutexHeld(sqlite3_mutex *p){
  return g.m.xMutexHeld(p->pReal);
}

................................................................................
** Allocate a countable mutex
*/
static sqlite3_mutex *counterMutexAlloc(int eType){
  sqlite3_mutex *pReal;
  sqlite3_mutex *pRet = 0;

  assert( g.isInit );
  assert(eType<8 && eType>=0);


  pReal = g.m.xMutexAlloc(eType);
  if( !pReal ) return 0;

  if( eType==SQLITE_MUTEX_FAST || eType==SQLITE_MUTEX_RECURSIVE ){
    pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex));
  }else{



    pRet = &g.aStatic[eType-2];
  }

  pRet->eType = eType;
  pRet->pReal = pReal;
  return pRet;
}

................................................................................
}

/*
** Enter a countable mutex.  Block until entry is safe.
*/
static void counterMutexEnter(sqlite3_mutex *p){
  assert( g.isInit );


  g.aCounter[p->eType]++;
  g.m.xMutexEnter(p->pReal);
}

/*
** Try to enter a mutex.  Return true on success.
*/
static int counterMutexTry(sqlite3_mutex *p){
  assert( g.isInit );


  g.aCounter[p->eType]++;
  if( g.disableTry ) return SQLITE_BUSY;
  return g.m.xMutexTry(p->pReal);
}

/* Leave a mutex
*/
................................................................................
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  Tcl_Obj *pRet;
  int ii;
  char *aName[8] = {
    "fast",        "recursive",   "static_master", "static_mem", 
    "static_open", "static_prng", "static_lru",    "static_pmem"
  };

  if( objc!=1 ){
    Tcl_WrongNumArgs(interp, 1, objv, "");
    return TCL_ERROR;
  }

  pRet = Tcl_NewObj();
  Tcl_IncrRefCount(pRet);
  for(ii=0; ii<8; ii++){
    Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1));
    Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii]));
  }
  Tcl_SetObjResult(interp, pRet);
  Tcl_DecrRefCount(pRet);

  return TCL_OK;
................................................................................
  int ii;

  if( objc!=1 ){
    Tcl_WrongNumArgs(interp, 1, objv, "");
    return TCL_ERROR;
  }

  for(ii=0; ii<8; ii++){
    g.aCounter[ii] = 0;
  }
  return TCL_OK;
}

/*
** Create and free a mutex.  Return the mutex pointer.  The pointer
................................................................................
    db = *((sqlite3 **)info.objClientData);
  }else{
    db = (sqlite3*)sqlite3TestTextToPtr(zCmd);
  }
  assert( db );
  return db;
}



















































static int test_enter_db_mutex(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
................................................................................
  static struct {
    char *zName;
    Tcl_ObjCmdProc *xProc;
  } aCmd[] = {
    { "sqlite3_shutdown",        (Tcl_ObjCmdProc*)test_shutdown },
    { "sqlite3_initialize",      (Tcl_ObjCmdProc*)test_initialize },
    { "sqlite3_config",          (Tcl_ObjCmdProc*)test_config },




    { "enter_db_mutex",          (Tcl_ObjCmdProc*)test_enter_db_mutex },
    { "leave_db_mutex",          (Tcl_ObjCmdProc*)test_leave_db_mutex },

    { "alloc_dealloc_mutex",     (Tcl_ObjCmdProc*)test_alloc_mutex },
    { "install_mutex_counters",  (Tcl_ObjCmdProc*)test_install_mutex_counters },
    { "read_mutex_counters",     (Tcl_ObjCmdProc*)test_read_mutex_counters },







>
>


>
>
>
>
>
>
>









|
|
|
|
|
|
|







 







|
>







>
>
>
|







 







>
>









>
>







 







<
<
<
<








|







 







|







 







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







 







>
>
>







15
16
17
18
19
20
21
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
..
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
...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
...
258
259
260
261
262
263
264




265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
...
379
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
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
#include "tcl.h"
#include "sqlite3.h"
#include "sqliteInt.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#define MAX_MUTEXES (SQLITE_MUTEX_STATIC_VFS3+1)

/* defined in main.c */
extern const char *sqlite3ErrName(int);

static const char *aName[MAX_MUTEXES+1] = {
  "fast",        "recursive",   "static_master", "static_mem",
  "static_open", "static_prng", "static_lru",    "static_pmem",
  "static_app1", "static_app2", "static_app3",   "static_vfs1",
  "static_vfs2", "static_vfs3", 0
};

/* A countable mutex */
struct sqlite3_mutex {
  sqlite3_mutex *pReal;
  int eType;
};

/* State variables */
static struct test_mutex_globals {
  int isInstalled;           /* True if installed */
  int disableInit;           /* True to cause sqlite3_initalize() to fail */
  int disableTry;            /* True to force sqlite3_mutex_try() to fail */
  int isInit;                /* True if initialized */
  sqlite3_mutex_methods m;   /* Interface to "real" mutex system */
  int aCounter[MAX_MUTEXES]; /* Number of grabs of each type of mutex */
  sqlite3_mutex aStatic[MAX_MUTEXES]; /* The static mutexes */
} g = {0};

/* Return true if the countable mutex is currently held */
static int counterMutexHeld(sqlite3_mutex *p){
  return g.m.xMutexHeld(p->pReal);
}

................................................................................
** Allocate a countable mutex
*/
static sqlite3_mutex *counterMutexAlloc(int eType){
  sqlite3_mutex *pReal;
  sqlite3_mutex *pRet = 0;

  assert( g.isInit );
  assert( eType>=SQLITE_MUTEX_FAST );
  assert( eType<=SQLITE_MUTEX_STATIC_VFS3 );

  pReal = g.m.xMutexAlloc(eType);
  if( !pReal ) return 0;

  if( eType==SQLITE_MUTEX_FAST || eType==SQLITE_MUTEX_RECURSIVE ){
    pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex));
  }else{
    int eStaticType = eType - (SQLITE_MUTEX_RECURSIVE + 1);
    assert( eStaticType>=0 );
    assert( eStaticType<MAX_MUTEXES );
    pRet = &g.aStatic[eStaticType];
  }

  pRet->eType = eType;
  pRet->pReal = pReal;
  return pRet;
}

................................................................................
}

/*
** Enter a countable mutex.  Block until entry is safe.
*/
static void counterMutexEnter(sqlite3_mutex *p){
  assert( g.isInit );
  assert( p->eType>=0 );
  assert( p->eType<MAX_MUTEXES );
  g.aCounter[p->eType]++;
  g.m.xMutexEnter(p->pReal);
}

/*
** Try to enter a mutex.  Return true on success.
*/
static int counterMutexTry(sqlite3_mutex *p){
  assert( g.isInit );
  assert( p->eType>=0 );
  assert( p->eType<MAX_MUTEXES );
  g.aCounter[p->eType]++;
  if( g.disableTry ) return SQLITE_BUSY;
  return g.m.xMutexTry(p->pReal);
}

/* Leave a mutex
*/
................................................................................
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  Tcl_Obj *pRet;
  int ii;





  if( objc!=1 ){
    Tcl_WrongNumArgs(interp, 1, objv, "");
    return TCL_ERROR;
  }

  pRet = Tcl_NewObj();
  Tcl_IncrRefCount(pRet);
  for(ii=0; ii<MAX_MUTEXES; ii++){
    Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1));
    Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii]));
  }
  Tcl_SetObjResult(interp, pRet);
  Tcl_DecrRefCount(pRet);

  return TCL_OK;
................................................................................
  int ii;

  if( objc!=1 ){
    Tcl_WrongNumArgs(interp, 1, objv, "");
    return TCL_ERROR;
  }

  for(ii=0; ii<MAX_MUTEXES; ii++){
    g.aCounter[ii] = 0;
  }
  return TCL_OK;
}

/*
** Create and free a mutex.  Return the mutex pointer.  The pointer
................................................................................
    db = *((sqlite3 **)info.objClientData);
  }else{
    db = (sqlite3*)sqlite3TestTextToPtr(zCmd);
  }
  assert( db );
  return db;
}

static sqlite3_mutex *getStaticMutexPointer(
  Tcl_Interp *pInterp,
  Tcl_Obj *pObj
){
  int iMutex;
  if( Tcl_GetIndexFromObj(pInterp, pObj, aName, "mutex name", 0, &iMutex) ){
    return 0;
  }
  assert( iMutex!=SQLITE_MUTEX_FAST && iMutex!=SQLITE_MUTEX_RECURSIVE );
  return counterMutexAlloc(iMutex);
}

static int test_enter_static_mutex(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_mutex *pMutex;
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "NAME");
    return TCL_ERROR;
  }
  pMutex = getStaticMutexPointer(interp, objv[1]);
  if( !pMutex ){
    return TCL_ERROR;
  }
  sqlite3_mutex_enter(pMutex);
  return TCL_OK;
}

static int test_leave_static_mutex(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_mutex *pMutex;
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "NAME");
    return TCL_ERROR;
  }
  pMutex = getStaticMutexPointer(interp, objv[1]);
  if( !pMutex ){
    return TCL_ERROR;
  }
  sqlite3_mutex_leave(pMutex);
  return TCL_OK;
}

static int test_enter_db_mutex(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
................................................................................
  static struct {
    char *zName;
    Tcl_ObjCmdProc *xProc;
  } aCmd[] = {
    { "sqlite3_shutdown",        (Tcl_ObjCmdProc*)test_shutdown },
    { "sqlite3_initialize",      (Tcl_ObjCmdProc*)test_initialize },
    { "sqlite3_config",          (Tcl_ObjCmdProc*)test_config },

    { "enter_static_mutex",      (Tcl_ObjCmdProc*)test_enter_static_mutex },
    { "leave_static_mutex",      (Tcl_ObjCmdProc*)test_leave_static_mutex },

    { "enter_db_mutex",          (Tcl_ObjCmdProc*)test_enter_db_mutex },
    { "leave_db_mutex",          (Tcl_ObjCmdProc*)test_leave_db_mutex },

    { "alloc_dealloc_mutex",     (Tcl_ObjCmdProc*)test_alloc_mutex },
    { "install_mutex_counters",  (Tcl_ObjCmdProc*)test_install_mutex_counters },
    { "read_mutex_counters",     (Tcl_ObjCmdProc*)test_read_mutex_counters },

Changes to test/mutex1.test.

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
98
99
100
101
102
103
104

105

106
107
108

109
110

111
112
113
114
115
116
117
...
125
126
127
128
129
130
131

132


















133
134
135
136
137
138
139
140
141
    set var($name) $value
    incr var(total) $value
  }
}

#-------------------------------------------------------------------------
# Tests mutex1-1.* test that sqlite3_config() returns SQLITE_MISUSE if
# is called at the wrong time. And that the first time sqlite3_initialize 
# is called it obtains the 'static_master' mutex 3 times and a recursive
# mutex (sqlite3Config.pInitMutex) twice. Subsequent calls are no-ops 
# that do not require any mutexes.
#
do_test mutex1-1.0 {
  install_mutex_counters 1
} {SQLITE_MISUSE}

do_test mutex1-1.1 {
................................................................................
#   * Single-threaded mode.
#
ifcapable threadsafe&&shared_cache {
  set enable_shared_cache [sqlite3_enable_shared_cache 1]
  foreach {mode mutexes} {
    singlethread {}
    multithread  {

      fast static_lru static_master static_mem static_open static_prng 

      static_pmem
    }
    serialized  {

      fast recursive static_lru static_master static_mem static_open 
      static_prng static_pmem

    }
  } {

    do_test mutex1.2.$mode.1 {
      catch {db close}
      sqlite3_shutdown
      sqlite3_config $mode
................................................................................
      db eval {
        INSERT INTO abc VALUES(1, 2, 3);
      }
    } {}
    ifcapable !memorymanage {
      regsub { static_lru} $mutexes {} mutexes
    }

    do_test mutex1.2.$mode.3 {


















      mutex_counters counters
  
      set res [list]
      foreach {key value} [array get counters] {
        if {$key ne "total" && $value > 0} {
          lappend res $key
        }
      }
      lsort $res







|

|







 







>
|
>
|


>
|
|
>







 







>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
    set var($name) $value
    incr var(total) $value
  }
}

#-------------------------------------------------------------------------
# Tests mutex1-1.* test that sqlite3_config() returns SQLITE_MISUSE if
# is called at the wrong time. And that the first time sqlite3_initialize
# is called it obtains the 'static_master' mutex 3 times and a recursive
# mutex (sqlite3Config.pInitMutex) twice. Subsequent calls are no-ops
# that do not require any mutexes.
#
do_test mutex1-1.0 {
  install_mutex_counters 1
} {SQLITE_MISUSE}

do_test mutex1-1.1 {
................................................................................
#   * Single-threaded mode.
#
ifcapable threadsafe&&shared_cache {
  set enable_shared_cache [sqlite3_enable_shared_cache 1]
  foreach {mode mutexes} {
    singlethread {}
    multithread  {
      fast static_app1 static_app2 static_app3
      static_lru static_master static_mem static_open
      static_prng static_pmem static_vfs1 static_vfs2
      static_vfs3
    }
    serialized  {
      fast recursive static_app1 static_app2
      static_app3 static_lru static_master static_mem
      static_open static_prng static_pmem static_vfs1
      static_vfs2 static_vfs3
    }
  } {

    do_test mutex1.2.$mode.1 {
      catch {db close}
      sqlite3_shutdown
      sqlite3_config $mode
................................................................................
      db eval {
        INSERT INTO abc VALUES(1, 2, 3);
      }
    } {}
    ifcapable !memorymanage {
      regsub { static_lru} $mutexes {} mutexes
    }
    if {$mode ne "singlethread"} {
      do_test mutex1.2.$mode.3 {
        #
        # NOTE: Make sure all the app and vfs mutexes get used.
        #
        enter_static_mutex static_app1
        leave_static_mutex static_app1
        enter_static_mutex static_app2
        leave_static_mutex static_app2
        enter_static_mutex static_app3
        leave_static_mutex static_app3
        enter_static_mutex static_vfs1
        leave_static_mutex static_vfs1
        enter_static_mutex static_vfs2
        leave_static_mutex static_vfs2
        enter_static_mutex static_vfs3
        leave_static_mutex static_vfs3
      } {}
    }
    do_test mutex1.2.$mode.4 {
      mutex_counters counters

      set res [list]
      foreach {key value} [array get counters] {
        if {$key ne "total" && $value > 0} {
          lappend res $key
        }
      }
      lsort $res