modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/test_mutex.c (about)

     1  /*
     2  ** 2008 June 18
     3  **
     4  ** The author disclaims copyright to this source code.  In place of
     5  ** a legal notice, here is a blessing:
     6  **
     7  **    May you do good and not evil.
     8  **    May you find forgiveness for yourself and forgive others.
     9  **    May you share freely, never taking more than you give.
    10  **
    11  *************************************************************************
    12  ** This file contains test logic for the sqlite3_mutex interfaces.
    13  */
    14  
    15  #if defined(INCLUDE_SQLITE_TCL_H)
    16  #  include "sqlite_tcl.h"
    17  #else
    18  #  include "tcl.h"
    19  #endif
    20  #include "sqlite3.h"
    21  #include "sqliteInt.h"
    22  #include <stdlib.h>
    23  #include <assert.h>
    24  #include <string.h>
    25  
    26  #define MAX_MUTEXES        (SQLITE_MUTEX_STATIC_VFS3+1)
    27  #define STATIC_MUTEXES     (MAX_MUTEXES-(SQLITE_MUTEX_RECURSIVE+1))
    28  
    29  /* defined in main.c */
    30  extern const char *sqlite3ErrName(int);
    31  
    32  static const char *aName[MAX_MUTEXES+1] = {
    33    "fast",        "recursive",   "static_master", "static_mem",
    34    "static_open", "static_prng", "static_lru",    "static_pmem",
    35    "static_app1", "static_app2", "static_app3",   "static_vfs1",
    36    "static_vfs2", "static_vfs3", 0
    37  };
    38  
    39  /* A countable mutex */
    40  struct sqlite3_mutex {
    41    sqlite3_mutex *pReal;
    42    int eType;
    43  };
    44  
    45  /* State variables */
    46  static struct test_mutex_globals {
    47    int isInstalled;           /* True if installed */
    48    int disableInit;           /* True to cause sqlite3_initalize() to fail */
    49    int disableTry;            /* True to force sqlite3_mutex_try() to fail */
    50    int isInit;                /* True if initialized */
    51    sqlite3_mutex_methods m;   /* Interface to "real" mutex system */
    52    int aCounter[MAX_MUTEXES]; /* Number of grabs of each type of mutex */
    53    sqlite3_mutex aStatic[STATIC_MUTEXES]; /* The static mutexes */
    54  } g = {0};
    55  
    56  /* Return true if the countable mutex is currently held */
    57  static int counterMutexHeld(sqlite3_mutex *p){
    58    return g.m.xMutexHeld(p->pReal);
    59  }
    60  
    61  /* Return true if the countable mutex is not currently held */
    62  static int counterMutexNotheld(sqlite3_mutex *p){
    63    return g.m.xMutexNotheld(p->pReal);
    64  }
    65  
    66  /* Initialize the countable mutex interface
    67  ** Or, if g.disableInit is non-zero, then do not initialize but instead
    68  ** return the value of g.disableInit as the result code.  This can be used
    69  ** to simulate an initialization failure.
    70  */
    71  static int counterMutexInit(void){ 
    72    int rc;
    73    if( g.disableInit ) return g.disableInit;
    74    rc = g.m.xMutexInit();
    75    g.isInit = 1;
    76    return rc;
    77  }
    78  
    79  /*
    80  ** Uninitialize the mutex subsystem
    81  */
    82  static int counterMutexEnd(void){ 
    83    g.isInit = 0;
    84    return g.m.xMutexEnd();
    85  }
    86  
    87  /*
    88  ** Allocate a countable mutex
    89  */
    90  static sqlite3_mutex *counterMutexAlloc(int eType){
    91    sqlite3_mutex *pReal;
    92    sqlite3_mutex *pRet = 0;
    93  
    94    assert( g.isInit );
    95    assert( eType>=SQLITE_MUTEX_FAST );
    96    assert( eType<=SQLITE_MUTEX_STATIC_VFS3 );
    97  
    98    pReal = g.m.xMutexAlloc(eType);
    99    if( !pReal ) return 0;
   100  
   101    if( eType==SQLITE_MUTEX_FAST || eType==SQLITE_MUTEX_RECURSIVE ){
   102      pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex));
   103    }else{
   104      int eStaticType = eType - (MAX_MUTEXES - STATIC_MUTEXES);
   105      assert( eStaticType>=0 );
   106      assert( eStaticType<STATIC_MUTEXES );
   107      pRet = &g.aStatic[eStaticType];
   108    }
   109  
   110    pRet->eType = eType;
   111    pRet->pReal = pReal;
   112    return pRet;
   113  }
   114  
   115  /*
   116  ** Free a countable mutex
   117  */
   118  static void counterMutexFree(sqlite3_mutex *p){
   119    assert( g.isInit );
   120    g.m.xMutexFree(p->pReal);
   121    if( p->eType==SQLITE_MUTEX_FAST || p->eType==SQLITE_MUTEX_RECURSIVE ){
   122      free(p);
   123    }
   124  }
   125  
   126  /*
   127  ** Enter a countable mutex.  Block until entry is safe.
   128  */
   129  static void counterMutexEnter(sqlite3_mutex *p){
   130    assert( g.isInit );
   131    assert( p->eType>=0 );
   132    assert( p->eType<MAX_MUTEXES );
   133    g.aCounter[p->eType]++;
   134    g.m.xMutexEnter(p->pReal);
   135  }
   136  
   137  /*
   138  ** Try to enter a mutex.  Return true on success.
   139  */
   140  static int counterMutexTry(sqlite3_mutex *p){
   141    assert( g.isInit );
   142    assert( p->eType>=0 );
   143    assert( p->eType<MAX_MUTEXES );
   144    g.aCounter[p->eType]++;
   145    if( g.disableTry ) return SQLITE_BUSY;
   146    return g.m.xMutexTry(p->pReal);
   147  }
   148  
   149  /* Leave a mutex
   150  */
   151  static void counterMutexLeave(sqlite3_mutex *p){
   152    assert( g.isInit );
   153    g.m.xMutexLeave(p->pReal);
   154  }
   155  
   156  /*
   157  ** sqlite3_shutdown
   158  */
   159  static int SQLITE_TCLAPI test_shutdown(
   160    void * clientData,
   161    Tcl_Interp *interp,
   162    int objc,
   163    Tcl_Obj *CONST objv[]
   164  ){
   165    int rc;
   166  
   167    if( objc!=1 ){
   168      Tcl_WrongNumArgs(interp, 1, objv, "");
   169      return TCL_ERROR;
   170    }
   171  
   172    rc = sqlite3_shutdown();
   173    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
   174    return TCL_OK;
   175  }
   176  
   177  /*
   178  ** sqlite3_initialize
   179  */
   180  static int SQLITE_TCLAPI test_initialize(
   181    void * clientData,
   182    Tcl_Interp *interp,
   183    int objc,
   184    Tcl_Obj *CONST objv[]
   185  ){
   186    int rc;
   187  
   188    if( objc!=1 ){
   189      Tcl_WrongNumArgs(interp, 1, objv, "");
   190      return TCL_ERROR;
   191    }
   192  
   193    rc = sqlite3_initialize();
   194    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
   195    return TCL_OK;
   196  }
   197  
   198  /*
   199  ** install_mutex_counters BOOLEAN
   200  */
   201  static int SQLITE_TCLAPI test_install_mutex_counters(
   202    void * clientData,
   203    Tcl_Interp *interp,
   204    int objc,
   205    Tcl_Obj *CONST objv[]
   206  ){
   207    int rc = SQLITE_OK;
   208    int isInstall;
   209  
   210    sqlite3_mutex_methods counter_methods = {
   211      counterMutexInit,
   212      counterMutexEnd,
   213      counterMutexAlloc,
   214      counterMutexFree,
   215      counterMutexEnter,
   216      counterMutexTry,
   217      counterMutexLeave,
   218      counterMutexHeld,
   219      counterMutexNotheld
   220    };
   221  
   222    if( objc!=2 ){
   223      Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
   224      return TCL_ERROR;
   225    }
   226    if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
   227      return TCL_ERROR;
   228    }
   229  
   230    assert(isInstall==0 || isInstall==1);
   231    assert(g.isInstalled==0 || g.isInstalled==1);
   232    if( isInstall==g.isInstalled ){
   233      Tcl_AppendResult(interp, "mutex counters are ", 0);
   234      Tcl_AppendResult(interp, isInstall?"already installed":"not installed", 0);
   235      return TCL_ERROR;
   236    }
   237  
   238    if( isInstall ){
   239      assert( g.m.xMutexAlloc==0 );
   240      rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m);
   241      if( rc==SQLITE_OK ){
   242        sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods);
   243      }
   244      g.disableTry = 0;
   245    }else{
   246      assert( g.m.xMutexAlloc );
   247      rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m);
   248      memset(&g.m, 0, sizeof(sqlite3_mutex_methods));
   249    }
   250  
   251    if( rc==SQLITE_OK ){
   252      g.isInstalled = isInstall;
   253    }
   254  
   255    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
   256    return TCL_OK;
   257  }
   258  
   259  /*
   260  ** read_mutex_counters
   261  */
   262  static int SQLITE_TCLAPI test_read_mutex_counters(
   263    void * clientData,
   264    Tcl_Interp *interp,
   265    int objc,
   266    Tcl_Obj *CONST objv[]
   267  ){
   268    Tcl_Obj *pRet;
   269    int ii;
   270  
   271    if( objc!=1 ){
   272      Tcl_WrongNumArgs(interp, 1, objv, "");
   273      return TCL_ERROR;
   274    }
   275  
   276    pRet = Tcl_NewObj();
   277    Tcl_IncrRefCount(pRet);
   278    for(ii=0; ii<MAX_MUTEXES; ii++){
   279      Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1));
   280      Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii]));
   281    }
   282    Tcl_SetObjResult(interp, pRet);
   283    Tcl_DecrRefCount(pRet);
   284  
   285    return TCL_OK;
   286  }
   287  
   288  /*
   289  ** clear_mutex_counters
   290  */
   291  static int SQLITE_TCLAPI test_clear_mutex_counters(
   292    void * clientData,
   293    Tcl_Interp *interp,
   294    int objc,
   295    Tcl_Obj *CONST objv[]
   296  ){
   297    int ii;
   298  
   299    if( objc!=1 ){
   300      Tcl_WrongNumArgs(interp, 1, objv, "");
   301      return TCL_ERROR;
   302    }
   303  
   304    for(ii=0; ii<MAX_MUTEXES; ii++){
   305      g.aCounter[ii] = 0;
   306    }
   307    return TCL_OK;
   308  }
   309  
   310  /*
   311  ** Create and free a mutex.  Return the mutex pointer.  The pointer
   312  ** will be invalid since the mutex has already been freed.  The
   313  ** return pointer just checks to see if the mutex really was allocated.
   314  */
   315  static int SQLITE_TCLAPI test_alloc_mutex(
   316    void * clientData,
   317    Tcl_Interp *interp,
   318    int objc,
   319    Tcl_Obj *CONST objv[]
   320  ){
   321  #if SQLITE_THREADSAFE
   322    sqlite3_mutex *p = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
   323    char zBuf[100];
   324    sqlite3_mutex_free(p);
   325    sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p);
   326    Tcl_AppendResult(interp, zBuf, (char*)0);
   327  #endif
   328    return TCL_OK;
   329  }
   330  
   331  /*
   332  ** sqlite3_config OPTION
   333  **
   334  ** OPTION can be either one of the keywords:
   335  **
   336  **            SQLITE_CONFIG_SINGLETHREAD
   337  **            SQLITE_CONFIG_MULTITHREAD
   338  **            SQLITE_CONFIG_SERIALIZED
   339  **
   340  ** Or OPTION can be an raw integer.
   341  */
   342  static int SQLITE_TCLAPI test_config(
   343    void * clientData,
   344    Tcl_Interp *interp,
   345    int objc,
   346    Tcl_Obj *CONST objv[]
   347  ){
   348    struct ConfigOption {
   349      const char *zName;
   350      int iValue;
   351    } aOpt[] = {
   352      {"singlethread", SQLITE_CONFIG_SINGLETHREAD},
   353      {"multithread",  SQLITE_CONFIG_MULTITHREAD},
   354      {"serialized",   SQLITE_CONFIG_SERIALIZED},
   355      {0, 0}
   356    };
   357    int s = sizeof(struct ConfigOption);
   358    int i;
   359    int rc;
   360  
   361    if( objc!=2 ){
   362      Tcl_WrongNumArgs(interp, 1, objv, "");
   363      return TCL_ERROR;
   364    }
   365  
   366    if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){
   367      if( Tcl_GetIntFromObj(interp, objv[1], &i) ){
   368        return TCL_ERROR;
   369      }
   370    }else{
   371      i = aOpt[i].iValue;
   372    }
   373  
   374    rc = sqlite3_config(i);
   375    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
   376    return TCL_OK;
   377  }
   378  
   379  static sqlite3 *getDbPointer(Tcl_Interp *pInterp, Tcl_Obj *pObj){
   380    sqlite3 *db;
   381    Tcl_CmdInfo info;
   382    char *zCmd = Tcl_GetString(pObj);
   383    if( Tcl_GetCommandInfo(pInterp, zCmd, &info) ){
   384      db = *((sqlite3 **)info.objClientData);
   385    }else{
   386      db = (sqlite3*)sqlite3TestTextToPtr(zCmd);
   387    }
   388    assert( db );
   389    return db;
   390  }
   391  
   392  static sqlite3_mutex *getStaticMutexPointer(
   393    Tcl_Interp *pInterp,
   394    Tcl_Obj *pObj
   395  ){
   396    int iMutex;
   397    if( Tcl_GetIndexFromObj(pInterp, pObj, aName, "mutex name", 0, &iMutex) ){
   398      return 0;
   399    }
   400    assert( iMutex!=SQLITE_MUTEX_FAST && iMutex!=SQLITE_MUTEX_RECURSIVE );
   401    return counterMutexAlloc(iMutex);
   402  }
   403  
   404  static int SQLITE_TCLAPI test_enter_static_mutex(
   405    void * clientData,
   406    Tcl_Interp *interp,
   407    int objc,
   408    Tcl_Obj *CONST objv[]
   409  ){
   410    sqlite3_mutex *pMutex;
   411    if( objc!=2 ){
   412      Tcl_WrongNumArgs(interp, 1, objv, "NAME");
   413      return TCL_ERROR;
   414    }
   415    pMutex = getStaticMutexPointer(interp, objv[1]);
   416    if( !pMutex ){
   417      return TCL_ERROR;
   418    }
   419    sqlite3_mutex_enter(pMutex);
   420    return TCL_OK;
   421  }
   422  
   423  static int SQLITE_TCLAPI test_leave_static_mutex(
   424    void * clientData,
   425    Tcl_Interp *interp,
   426    int objc,
   427    Tcl_Obj *CONST objv[]
   428  ){
   429    sqlite3_mutex *pMutex;
   430    if( objc!=2 ){
   431      Tcl_WrongNumArgs(interp, 1, objv, "NAME");
   432      return TCL_ERROR;
   433    }
   434    pMutex = getStaticMutexPointer(interp, objv[1]);
   435    if( !pMutex ){
   436      return TCL_ERROR;
   437    }
   438    sqlite3_mutex_leave(pMutex);
   439    return TCL_OK;
   440  }
   441  
   442  static int SQLITE_TCLAPI test_enter_db_mutex(
   443    void * clientData,
   444    Tcl_Interp *interp,
   445    int objc,
   446    Tcl_Obj *CONST objv[]
   447  ){
   448    sqlite3 *db;
   449    if( objc!=2 ){
   450      Tcl_WrongNumArgs(interp, 1, objv, "DB");
   451      return TCL_ERROR;
   452    }
   453    db = getDbPointer(interp, objv[1]);
   454    if( !db ){
   455      return TCL_ERROR;
   456    }
   457    sqlite3_mutex_enter(sqlite3_db_mutex(db));
   458    return TCL_OK;
   459  }
   460  
   461  static int SQLITE_TCLAPI test_leave_db_mutex(
   462    void * clientData,
   463    Tcl_Interp *interp,
   464    int objc,
   465    Tcl_Obj *CONST objv[]
   466  ){
   467    sqlite3 *db;
   468    if( objc!=2 ){
   469      Tcl_WrongNumArgs(interp, 1, objv, "DB");
   470      return TCL_ERROR;
   471    }
   472    db = getDbPointer(interp, objv[1]);
   473    if( !db ){
   474      return TCL_ERROR;
   475    }
   476    sqlite3_mutex_leave(sqlite3_db_mutex(db));
   477    return TCL_OK;
   478  }
   479  
   480  int Sqlitetest_mutex_Init(Tcl_Interp *interp){
   481    static struct {
   482      char *zName;
   483      Tcl_ObjCmdProc *xProc;
   484    } aCmd[] = {
   485      { "sqlite3_shutdown",        (Tcl_ObjCmdProc*)test_shutdown },
   486      { "sqlite3_initialize",      (Tcl_ObjCmdProc*)test_initialize },
   487      { "sqlite3_config",          (Tcl_ObjCmdProc*)test_config },
   488  
   489      { "enter_static_mutex",      (Tcl_ObjCmdProc*)test_enter_static_mutex },
   490      { "leave_static_mutex",      (Tcl_ObjCmdProc*)test_leave_static_mutex },
   491  
   492      { "enter_db_mutex",          (Tcl_ObjCmdProc*)test_enter_db_mutex },
   493      { "leave_db_mutex",          (Tcl_ObjCmdProc*)test_leave_db_mutex },
   494  
   495      { "alloc_dealloc_mutex",     (Tcl_ObjCmdProc*)test_alloc_mutex },
   496      { "install_mutex_counters",  (Tcl_ObjCmdProc*)test_install_mutex_counters },
   497      { "read_mutex_counters",     (Tcl_ObjCmdProc*)test_read_mutex_counters },
   498      { "clear_mutex_counters",    (Tcl_ObjCmdProc*)test_clear_mutex_counters },
   499    };
   500    int i;
   501    for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
   502      Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
   503    }
   504  
   505    Tcl_LinkVar(interp, "disable_mutex_init", 
   506                (char*)&g.disableInit, TCL_LINK_INT);
   507    Tcl_LinkVar(interp, "disable_mutex_try", 
   508                (char*)&g.disableTry, TCL_LINK_INT);
   509    return SQLITE_OK;
   510  }