mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-09 14:21:03 +03:00
Add experimental feature to detect threading bugs in apps that use
SQLITE_CONFIG_MULTITHREADED. Enabled at compile time using SQLITE_ENABLE_MULTITHREADED_CHECKS. FossilOrigin-Name: a66886ac13aa6d8ccbb6d673ddd00267c93e3ee1fbc158236fce3157d150868d
This commit is contained in:
181
src/mutex.c
181
src/mutex.c
@@ -26,6 +26,182 @@ static SQLITE_WSD int mutexIsInit = 0;
|
||||
|
||||
|
||||
#ifndef SQLITE_MUTEX_OMIT
|
||||
|
||||
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
|
||||
/*
|
||||
** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains
|
||||
** the implementation of a wrapper around the system default mutex
|
||||
** implementation (sqlite3DefaultMutex()).
|
||||
**
|
||||
** Most calls are passed directly through to the underlying default
|
||||
** mutex implementation. Except, if a mutex is configured by calling
|
||||
** sqlite3MutexWarnOnContention() on it, then if contention is ever
|
||||
** encountered within xMutexEnter() a warning is emitted via sqlite3_log().
|
||||
**
|
||||
** This type of mutex is used as the database handle mutex when testing
|
||||
** apps that usually use SQLITE_CONFIG_MULTITHREAD mode.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS
|
||||
** is defined.
|
||||
*/
|
||||
typedef struct CheckMutex CheckMutex;
|
||||
struct CheckMutex {
|
||||
int iType;
|
||||
sqlite3_mutex *mutex;
|
||||
};
|
||||
|
||||
/*
|
||||
** Pointer to real mutex methods object used by the CheckMutex
|
||||
** implementation. Set by checkMutexInit().
|
||||
*/
|
||||
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
|
||||
|
||||
/*
|
||||
** Initialize and deinitialize the mutex subsystem.
|
||||
*/
|
||||
static int checkMutexInit(void){
|
||||
pGlobalMutexMethods = sqlite3DefaultMutex();
|
||||
return SQLITE_OK;
|
||||
}
|
||||
static int checkMutexEnd(void){
|
||||
pGlobalMutexMethods = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate a mutex.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a mutex.
|
||||
*/
|
||||
static void checkMutexFree(sqlite3_mutex *p){
|
||||
#if SQLITE_ENABLE_API_ARMOR
|
||||
if( 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
|
||||
}
|
||||
|
||||
/*
|
||||
** Enter the mutex.
|
||||
*/
|
||||
static void checkMutexEnter(sqlite3_mutex *p){
|
||||
CheckMutex *pCheck = (CheckMutex*)p;
|
||||
if( pCheck->iType<0 ){
|
||||
if( SQLITE_OK==pGlobalMutexMethods->xMutexTry(pCheck->mutex) ){
|
||||
return;
|
||||
}
|
||||
sqlite3_log(SQLITE_MISUSE,
|
||||
"illegal multi-threaded access to database connection"
|
||||
);
|
||||
}
|
||||
pGlobalMutexMethods->xMutexEnter(pCheck->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Enter the mutex (do not block).
|
||||
*/
|
||||
static int checkMutexTry(sqlite3_mutex *p){
|
||||
CheckMutex *pCheck = (CheckMutex*)p;
|
||||
return pGlobalMutexMethods->xMutexTry(pCheck->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Leave the 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;
|
||||
}
|
||||
|
||||
/*
|
||||
** Mark the SQLITE_MUTEX_RECURSIVE mutex passed as the only argument as
|
||||
** one on which there should be no contention.
|
||||
*/
|
||||
void sqlite3MutexWarnOnContention(sqlite3_mutex *p){
|
||||
if( sqlite3GlobalConfig.mutex.xMutexAlloc==checkMutexAlloc ){
|
||||
CheckMutex *pCheck = (CheckMutex*)p;
|
||||
assert( pCheck->iType==SQLITE_MUTEX_RECURSIVE );
|
||||
pCheck->iType = -1;
|
||||
}
|
||||
}
|
||||
#endif /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */
|
||||
|
||||
/*
|
||||
** Initialize the mutex system.
|
||||
*/
|
||||
@@ -41,7 +217,11 @@ int sqlite3MutexInit(void){
|
||||
sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
|
||||
|
||||
if( sqlite3GlobalConfig.bCoreMutex ){
|
||||
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
|
||||
pFrom = multiThreadedCheckMutex();
|
||||
#else
|
||||
pFrom = sqlite3DefaultMutex();
|
||||
#endif
|
||||
}else{
|
||||
pFrom = sqlite3NoopMutex();
|
||||
}
|
||||
@@ -167,3 +347,4 @@ int sqlite3_mutex_notheld(sqlite3_mutex *p){
|
||||
#endif
|
||||
|
||||
#endif /* !defined(SQLITE_MUTEX_OMIT) */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user