#include "sqliteInt.h"
#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT)
static SQLITE_WSD int mutexIsInit = 0;
#endif
#ifndef SQLITE_MUTEX_OMIT
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
typedef struct CheckMutex CheckMutex;
struct CheckMutex {
int iType;
sqlite3_mutex *mutex;
};
#define SQLITE_MUTEX_WARNONCONTENTION (-1)
static SQLITE_WSD const sqlite3_mutex_methods *pGlobalMutexMethods;
#ifdef SQLITE_DEBUG
static int checkMutexHeld(sqlite3_mutex *p){
return pGlobalMutexMethods->xMutexHeld(((CheckMutex*)p)->mutex);
}
static int checkMutexNotheld(sqlite3_mutex *p){
return pGlobalMutexMethods->xMutexNotheld(((CheckMutex*)p)->mutex);
}
#endif
static int checkMutexInit(void){
pGlobalMutexMethods = sqlite3DefaultMutex();
return SQLITE_OK;
}
static int checkMutexEnd(void){
pGlobalMutexMethods = 0;
return SQLITE_OK;
}
static sqlite3_mutex *checkMutexAlloc(int iType){
static CheckMutex staticMutexes[] = {
{2, 0}, {3, 0}, {4, 0}, {5, 0},
{6, 0}, {7, 0}, {8, 0}, {9, 0},
{10, 0}, {11, 0}, {12, 0}, {13, 0}
};
CheckMutex *p = 0;
assert( SQLITE_MUTEX_RECURSIVE==1 && SQLITE_MUTEX_FAST==0 );
if( iType<2 ){
p = sqlite3MallocZero(sizeof(CheckMutex));
if( p==0 ) return 0;
p->iType = iType;
}else{
#ifdef SQLITE_ENABLE_API_ARMOR
if( iType-2>=ArraySize(staticMutexes) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
p = &staticMutexes[iType-2];
}
if( p->mutex==0 ){
p->mutex = pGlobalMutexMethods->xMutexAlloc(iType);
if( p->mutex==0 ){
if( iType<2 ){
sqlite3_free(p);
}
p = 0;
}
}
return (sqlite3_mutex*)p;
}
static void checkMutexFree(sqlite3_mutex *p){
assert( SQLITE_MUTEX_RECURSIVE<2 );
assert( SQLITE_MUTEX_FAST<2 );
assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
#if SQLITE_ENABLE_API_ARMOR
if( ((CheckMutex*)p)->iType<2 )
#endif
{
CheckMutex *pCheck = (CheckMutex*)p;
pGlobalMutexMethods->xMutexFree(pCheck->mutex);
sqlite3_free(pCheck);
}
#ifdef SQLITE_ENABLE_API_ARMOR
else{
(void)SQLITE_MISUSE_BKPT;
}
#endif
}
static void checkMutexEnter(sqlite3_mutex *p){
CheckMutex *pCheck = (CheckMutex*)p;
if( pCheck->iType==SQLITE_MUTEX_WARNONCONTENTION ){
if( SQLITE_OK==pGlobalMutexMethods->xMutexTry(pCheck->mutex) ){
return;
}
sqlite3_log(SQLITE_MISUSE,
"illegal multi-threaded access to database connection"
);
}
pGlobalMutexMethods->xMutexEnter(pCheck->mutex);
}
static int checkMutexTry(sqlite3_mutex *p){
CheckMutex *pCheck = (CheckMutex*)p;
return pGlobalMutexMethods->xMutexTry(pCheck->mutex);
}
static void checkMutexLeave(sqlite3_mutex *p){
CheckMutex *pCheck = (CheckMutex*)p;
pGlobalMutexMethods->xMutexLeave(pCheck->mutex);
}
sqlite3_mutex_methods const *multiThreadedCheckMutex(void){
static const sqlite3_mutex_methods sMutex = {
checkMutexInit,
checkMutexEnd,
checkMutexAlloc,
checkMutexFree,
checkMutexEnter,
checkMutexTry,
checkMutexLeave,
#ifdef SQLITE_DEBUG
checkMutexHeld,
checkMutexNotheld
#else
0,
0
#endif
};
return &sMutex;
}
void sqlite3MutexWarnOnContention(sqlite3_mutex *p){
if( sqlite3GlobalConfig.mutex.xMutexAlloc==checkMutexAlloc ){
CheckMutex *pCheck = (CheckMutex*)p;
assert( pCheck->iType==SQLITE_MUTEX_RECURSIVE );
pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION;
}
}
#endif
int sqlite3MutexInit(void){
int rc = SQLITE_OK;
if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
sqlite3_mutex_methods const *pFrom;
sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
if( sqlite3GlobalConfig.bCoreMutex ){
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
pFrom = multiThreadedCheckMutex();
#else
pFrom = sqlite3DefaultMutex();
#endif
}else{
pFrom = sqlite3NoopMutex();
}
pTo->xMutexInit = pFrom->xMutexInit;
pTo->xMutexEnd = pFrom->xMutexEnd;
pTo->xMutexFree = pFrom->xMutexFree;
pTo->xMutexEnter = pFrom->xMutexEnter;
pTo->xMutexTry = pFrom->xMutexTry;
pTo->xMutexLeave = pFrom->xMutexLeave;
pTo->xMutexHeld = pFrom->xMutexHeld;
pTo->xMutexNotheld = pFrom->xMutexNotheld;
sqlite3MemoryBarrier();
pTo->xMutexAlloc = pFrom->xMutexAlloc;
}
assert( sqlite3GlobalConfig.mutex.xMutexInit );
rc = sqlite3GlobalConfig.mutex.xMutexInit();
#ifdef SQLITE_DEBUG
GLOBAL(int, mutexIsInit) = 1;
#endif
sqlite3MemoryBarrier();
return rc;
}
int sqlite3MutexEnd(void){
int rc = SQLITE_OK;
if( sqlite3GlobalConfig.mutex.xMutexEnd ){
rc = sqlite3GlobalConfig.mutex.xMutexEnd();
}
#ifdef SQLITE_DEBUG
GLOBAL(int, mutexIsInit) = 0;
#endif
return rc;
}
sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0;
#endif
assert( sqlite3GlobalConfig.mutex.xMutexAlloc );
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}
sqlite3_mutex *sqlite3MutexAlloc(int id){
if( !sqlite3GlobalConfig.bCoreMutex ){
return 0;
}
assert( GLOBAL(int, mutexIsInit) );
assert( sqlite3GlobalConfig.mutex.xMutexAlloc );
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}
void sqlite3_mutex_free(sqlite3_mutex *p){
if( p ){
assert( sqlite3GlobalConfig.mutex.xMutexFree );
sqlite3GlobalConfig.mutex.xMutexFree(p);
}
}
void sqlite3_mutex_enter(sqlite3_mutex *p){
if( p ){
assert( sqlite3GlobalConfig.mutex.xMutexEnter );
sqlite3GlobalConfig.mutex.xMutexEnter(p);
}
}
int sqlite3_mutex_try(sqlite3_mutex *p){
int rc = SQLITE_OK;
if( p ){
assert( sqlite3GlobalConfig.mutex.xMutexTry );
return sqlite3GlobalConfig.mutex.xMutexTry(p);
}
return rc;
}
void sqlite3_mutex_leave(sqlite3_mutex *p){
if( p ){
assert( sqlite3GlobalConfig.mutex.xMutexLeave );
sqlite3GlobalConfig.mutex.xMutexLeave(p);
}
}
#ifndef NDEBUG
int sqlite3_mutex_held(sqlite3_mutex *p){
assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );
return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
}
int sqlite3_mutex_notheld(sqlite3_mutex *p){
assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );
return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
}
#endif
#endif