Team Ai
Modelpublic

AryaWu/sqlite

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