| Index: third_party/sqlite/src/src/test_mutex.c
|
| diff --git a/third_party/sqlite/src/src/test_mutex.c b/third_party/sqlite/src/src/test_mutex.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0bb74375d8fd690fd5c4981399f4a2ba04875b7a
|
| --- /dev/null
|
| +++ b/third_party/sqlite/src/src/test_mutex.c
|
| @@ -0,0 +1,439 @@
|
| +/*
|
| +** 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.
|
| +**
|
| +*************************************************************************
|
| +** This file contains test logic for the sqlite3_mutex interfaces.
|
| +*/
|
| +
|
| +#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 = {0};
|
| +
|
| +/* 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_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;
|
| +}
|
| +
|
| +/*
|
| +** 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;
|
| +}
|
| +
|
| +static sqlite3 *getDbPointer(Tcl_Interp *pInterp, Tcl_Obj *pObj){
|
| + sqlite3 *db;
|
| + Tcl_CmdInfo info;
|
| + char *zCmd = Tcl_GetString(pObj);
|
| + if( Tcl_GetCommandInfo(pInterp, zCmd, &info) ){
|
| + 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[]
|
| +){
|
| + sqlite3 *db;
|
| + if( objc!=2 ){
|
| + Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
| + return TCL_ERROR;
|
| + }
|
| + db = getDbPointer(interp, objv[1]);
|
| + if( !db ){
|
| + return TCL_ERROR;
|
| + }
|
| + sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
| + return TCL_OK;
|
| +}
|
| +
|
| +static int test_leave_db_mutex(
|
| + void * clientData,
|
| + Tcl_Interp *interp,
|
| + int objc,
|
| + Tcl_Obj *CONST objv[]
|
| +){
|
| + sqlite3 *db;
|
| + if( objc!=2 ){
|
| + Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
| + return TCL_ERROR;
|
| + }
|
| + db = getDbPointer(interp, objv[1]);
|
| + if( !db ){
|
| + return TCL_ERROR;
|
| + }
|
| + sqlite3_mutex_leave(sqlite3_db_mutex(db));
|
| + 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 },
|
| +
|
| + { "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 },
|
| + { "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);
|
| + }
|
| +
|
| + 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;
|
| +}
|
|
|