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: 40b598c8392f030f6ed8c63ce81cb0426bb3984397c19c756215f6a569a40164
This commit is contained in:
commit
66a1520c73
19
manifest
19
manifest
@ -1,5 +1,5 @@
|
||||
C Update\stests\sto\sdeal\swith\sSQLITE_FAST_SECURE_DELETE.
|
||||
D 2017-11-28T00:52:14.148
|
||||
C Add\sexperimental\sfeature\sto\sdetect\sthreading\sbugs\sin\sapps\sthat\suse\nSQLITE_CONFIG_MULTITHREADED.\sEnabled\sat\scompile\stime\susing\nSQLITE_ENABLE_MULTITHREADED_CHECKS.
|
||||
D 2017-11-28T07:52:00.416
|
||||
F Makefile.in 6a879cbf01e37f9eac131414955f71774b566502d9a57ded1b8585b507503cb8
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc e5d7606238f55816da99f719969598df5b091aa2e9a6935c9412fcae8f53fc44
|
||||
@ -436,7 +436,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c cb67cc56ef2ddd13e6944b2c0dd08a920bcd9503230adef8b9928d338097c722
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c 20865b183bb8a3723d59cf1efffc3c50217eb452c1021d077b908c94da26b0b2
|
||||
F src/main.c 99ed3d45e315afb2ada049991db7944b1210663bb30bfd0b63103537c1ac25d0
|
||||
F src/main.c 6a0cc1c7b8ab92374effecdd7b92792b3273a255c70575b7d67bd9a4315e6d3a
|
||||
F src/malloc.c a02c9e69bc76bee0f639416b947a946412890b606301454727feadcb313536d6
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
@ -445,7 +445,7 @@ F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
|
||||
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
|
||||
F src/memjournal.c 6f3d36a0a8f72f48f6c3c722f04301ac64f2515435fa42924293e46fc7994661
|
||||
F src/msvc.h 4942752b6a253116baaa8de75256c51a459a5e81
|
||||
F src/mutex.c 8e45800ee78e0cd1f1f3fe8e398853307f4a085c
|
||||
F src/mutex.c 20172f2cc43c4542f7860ab6bafdd16965822c4e56650d62628059a48c7f43c4
|
||||
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
|
||||
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
|
||||
F src/mutex_unix.c 27bb6cc49485ee46711a6580ab7b3f1402211d23
|
||||
@ -476,7 +476,7 @@ F src/shell.c.in c441d7ddfbb8120cd8a7cde838ca5c9167311a7e400b1077c3ae6090aa420be
|
||||
F src/sqlite.h.in 8fd97993d48b50b9bade38c52f12d175942c9497c960905610c7b03a3e4b5818
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
|
||||
F src/sqliteInt.h 9b26fbab75ef426efae70d88ab535844d59de8954542b122c1d49af580a76f58
|
||||
F src/sqliteInt.h 4c910d9c0d88a90e8639a4f83ef05f701ccfe731cf593e757444074f01df4964
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@ -1678,7 +1678,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 465350e55ddaf30cfba7874653301de7238a9dc2bc5e1f800fc95de9360679f6
|
||||
R 5c3698b136ad7029a7e22749e9f1a061
|
||||
U drh
|
||||
Z 455c99a49ae132932748abfe00c111c4
|
||||
P e6b89304695be371978e65dddd710c8bd563c66b9c94d23165142b6c235c82e1 12a23c0a66fac5c9674120b390f6abaeaba3f7ff04693b281af1eefb93d6f47c
|
||||
R dd8aff31239aebcaa5e5379a4673912d
|
||||
T +closed 12a23c0a66fac5c9674120b390f6abaeaba3f7ff04693b281af1eefb93d6f47c
|
||||
U dan
|
||||
Z bdded6a608898929c58df7d45769809f
|
||||
|
@ -1 +1 @@
|
||||
e6b89304695be371978e65dddd710c8bd563c66b9c94d23165142b6c235c82e1
|
||||
40b598c8392f030f6ed8c63ce81cb0426bb3984397c19c756215f6a569a40164
|
10
src/main.c
10
src/main.c
@ -2822,6 +2822,7 @@ static int openDatabase(
|
||||
}else{
|
||||
isThreadsafe = sqlite3GlobalConfig.bFullMutex;
|
||||
}
|
||||
|
||||
if( flags & SQLITE_OPEN_PRIVATECACHE ){
|
||||
flags &= ~SQLITE_OPEN_SHAREDCACHE;
|
||||
}else if( sqlite3GlobalConfig.sharedCacheEnabled ){
|
||||
@ -2854,13 +2855,20 @@ static int openDatabase(
|
||||
/* Allocate the sqlite data structure */
|
||||
db = sqlite3MallocZero( sizeof(sqlite3) );
|
||||
if( db==0 ) goto opendb_out;
|
||||
if( isThreadsafe ){
|
||||
if( isThreadsafe
|
||||
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
|
||||
|| sqlite3GlobalConfig.bCoreMutex
|
||||
#endif
|
||||
){
|
||||
db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
|
||||
if( db->mutex==0 ){
|
||||
sqlite3_free(db);
|
||||
db = 0;
|
||||
goto opendb_out;
|
||||
}
|
||||
if( isThreadsafe==0 ){
|
||||
sqlite3MutexWarnOnContention(db->mutex);
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
db->errMask = 0xff;
|
||||
|
192
src/mutex.c
192
src/mutex.c
@ -26,6 +26,193 @@ 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. Variable CheckMutex.mutex is a pointer to the real mutex
|
||||
** allocated by the system mutex implementation. Variable iType is usually set
|
||||
** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST
|
||||
** or one of the static mutex identifiers. Or, if this is a recursive mutex
|
||||
** that has been configured using sqlite3MutexWarnOnContention(), it is
|
||||
** set to SQLITE_MUTEX_WARNONCONTENTION.
|
||||
*/
|
||||
typedef struct CheckMutex CheckMutex;
|
||||
struct CheckMutex {
|
||||
int iType;
|
||||
sqlite3_mutex *mutex;
|
||||
};
|
||||
|
||||
#define SQLITE_MUTEX_WARNONCONTENTION (-1)
|
||||
|
||||
/*
|
||||
** 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){
|
||||
assert( SQLITE_MUTEX_RECURSIVE<2 );
|
||||
assert( SQLITE_MUTEX_FAST<2 );
|
||||
assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
|
||||
|
||||
#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==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);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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 = SQLITE_MUTEX_WARNONCONTENTION;
|
||||
}
|
||||
}
|
||||
#endif /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */
|
||||
|
||||
/*
|
||||
** Initialize the mutex system.
|
||||
*/
|
||||
@ -41,7 +228,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 +358,4 @@ int sqlite3_mutex_notheld(sqlite3_mutex *p){
|
||||
#endif
|
||||
|
||||
#endif /* !defined(SQLITE_MUTEX_OMIT) */
|
||||
|
||||
|
@ -3590,6 +3590,12 @@ int sqlite3LookasideUsed(sqlite3*,int*);
|
||||
sqlite3_mutex *sqlite3Pcache1Mutex(void);
|
||||
sqlite3_mutex *sqlite3MallocMutex(void);
|
||||
|
||||
#if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT)
|
||||
void sqlite3MutexWarnOnContention(sqlite3_mutex*);
|
||||
#else
|
||||
# define sqlite3MutexWarnOnContention(x)
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
int sqlite3IsNaN(double);
|
||||
#else
|
||||
|
Loading…
x
Reference in New Issue
Block a user