persistentstorage/sqlite3api/TEST/SRC/test_mutex.c
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sqlite3api/TEST/SRC/test_mutex.c	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,387 @@
+/*
+** 2008 June 18
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+** 
+** $Id: test_mutex.c,v 1.11 2008/07/19 13:43:24 danielk1977 Exp $
+*/
+
+#include "tcl.h"
+#include "sqlite3.h"
+#include "sqliteInt.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+/* defined in test1.c */
+const char *sqlite3TestErrorName(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;
+
+/* Return true if the countable mutex is currently held */
+static int counterMutexHeld(sqlite3_mutex *p){
+  return g.m.xMutexHeld(p->pReal);
+}
+
+/* Return true if the countable mutex is not currently held */
+static int counterMutexNotheld(sqlite3_mutex *p){
+  return g.m.xMutexNotheld(p->pReal);
+}
+
+/* Initialize the countable mutex interface
+** Or, if g.disableInit is non-zero, then do not initialize but instead
+** return the value of g.disableInit as the result code.  This can be used
+** to simulate an initialization failure.
+*/
+static int counterMutexInit(void){ 
+  int rc;
+  if( g.disableInit ) return g.disableInit;
+  rc = g.m.xMutexInit();
+  g.isInit = 1;
+  return rc;
+}
+
+/*
+** Uninitialize the mutex subsystem
+*/
+static int counterMutexEnd(void){ 
+  g.isInit = 0;
+  return g.m.xMutexEnd();
+}
+
+/*
+** 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;
+}
+
+/*
+** Free a countable mutex
+*/
+static void counterMutexFree(sqlite3_mutex *p){
+  assert( g.isInit );
+  g.m.xMutexFree(p->pReal);
+  if( p->eType==SQLITE_MUTEX_FAST || p->eType==SQLITE_MUTEX_RECURSIVE ){
+    free(p);
+  }
+}
+
+/*
+** 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
+*/
+static void counterMutexLeave(sqlite3_mutex *p){
+  assert( g.isInit );
+  g.m.xMutexLeave(p->pReal);
+}
+
+/*
+** sqlite3_shutdown
+*/
+static int test_shutdown(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  int rc;
+
+  if( objc!=1 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "");
+    return TCL_ERROR;
+  }
+
+  rc = sqlite3_shutdown();
+  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
+  return TCL_OK;
+}
+
+/*
+** sqlite3_initialize
+*/
+static int test_initialize(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  int rc;
+
+  if( objc!=1 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "");
+    return TCL_ERROR;
+  }
+
+  rc = sqlite3_initialize();
+  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
+  return TCL_OK;
+}
+
+/*
+** install_mutex_counters BOOLEAN
+*/
+static int test_install_mutex_counters(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  int rc = SQLITE_OK;
+  int isInstall;
+
+  sqlite3_mutex_methods counter_methods = {
+    counterMutexInit,
+    counterMutexEnd,
+    counterMutexAlloc,
+    counterMutexFree,
+    counterMutexEnter,
+    counterMutexTry,
+    counterMutexLeave,
+    counterMutexHeld,
+    counterMutexNotheld
+  };
+
+  if( objc!=2 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
+    return TCL_ERROR;
+  }
+  if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
+    return TCL_ERROR;
+  }
+
+  assert(isInstall==0 || isInstall==1);
+  assert(g.isInstalled==0 || g.isInstalled==1);
+  if( isInstall==g.isInstalled ){
+    Tcl_AppendResult(interp, "mutex counters are ", 0);
+    Tcl_AppendResult(interp, isInstall?"already installed":"not installed", 0);
+    return TCL_ERROR;
+  }
+
+  if( isInstall ){
+    assert( g.m.xMutexAlloc==0 );
+    rc = sqlite3_config(SQLITE_CONFIG_GETMUTEX, &g.m);
+    if( rc==SQLITE_OK ){
+      sqlite3_config(SQLITE_CONFIG_MUTEX, &counter_methods);
+    }
+    g.disableTry = 0;
+  }else{
+    assert( g.m.xMutexAlloc );
+    rc = sqlite3_config(SQLITE_CONFIG_MUTEX, &g.m);
+    memset(&g.m, 0, sizeof(sqlite3_mutex_methods));
+  }
+
+  if( rc==SQLITE_OK ){
+    g.isInstalled = isInstall;
+  }
+
+  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
+  return TCL_OK;
+}
+
+/*
+** read_mutex_counters
+*/
+static int test_read_mutex_counters(
+  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_mem2", "static_prng", "static_lru",    "static_lru2"
+  };
+
+  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;
+}
+
+/*
+** clear_mutex_counters
+*/
+static int test_clear_mutex_counters(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  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
+** will be invalid since the mutex has already been freed.  The
+** return pointer just checks to see if the mutex really was allocated.
+*/
+static int test_alloc_mutex(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+#if SQLITE_THREADSAFE
+  sqlite3_mutex *p = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+  char zBuf[100];
+  sqlite3_mutex_free(p);
+  sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p);
+  Tcl_AppendResult(interp, zBuf, (char*)0);
+#endif
+  return TCL_OK;
+}
+
+/*
+** sqlite3_config OPTION
+**
+** OPTION can be either one of the keywords:
+**
+**            SQLITE_CONFIG_SINGLETHREAD
+**            SQLITE_CONFIG_MULTITHREAD
+**            SQLITE_CONFIG_SERIALIZED
+**
+** Or OPTION can be an raw integer.
+*/
+static int test_config(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  struct ConfigOption {
+    const char *zName;
+    int iValue;
+  } aOpt[] = {
+    {"singlethread", SQLITE_CONFIG_SINGLETHREAD},
+    {"multithread",  SQLITE_CONFIG_MULTITHREAD},
+    {"serialized",   SQLITE_CONFIG_SERIALIZED},
+    {0, 0}
+  };
+  int s = sizeof(struct ConfigOption);
+  int i;
+  int rc;
+
+  if( objc!=2 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "");
+    return TCL_ERROR;
+  }
+
+  if( Tcl_GetIndexFromObjStruct(interp, objv[1], aOpt, s, "flag", 0, &i) ){
+    if( Tcl_GetIntFromObj(interp, objv[1], &i) ){
+      return TCL_ERROR;
+    }
+  }else{
+    i = aOpt[i].iValue;
+  }
+
+  rc = sqlite3_config(i);
+  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
+  return TCL_OK;
+}
+
+int Sqlitetest_mutex_Init(Tcl_Interp *interp){
+  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 },
+
+    { "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 },
+    { "clear_mutex_counters",    (Tcl_ObjCmdProc*)test_clear_mutex_counters },
+  };
+  int i;
+  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
+    Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
+  }
+  memset(&g, 0, sizeof(g));
+
+  Tcl_LinkVar(interp, "disable_mutex_init", 
+              (char*)&g.disableInit, TCL_LINK_INT);
+  Tcl_LinkVar(interp, "disable_mutex_try", 
+              (char*)&g.disableTry, TCL_LINK_INT);
+  return SQLITE_OK;
+}