New mutex implementation for both Unix and windows. (CVS 4291)
FossilOrigin-Name: e144b81f699ca991cc4fa12a487156391db0b367
This commit is contained in:
parent
e806566248
commit
bff101efd7
14
manifest
14
manifest
@ -1,5 +1,5 @@
|
||||
C fix\scleanup\sby\sremoving\ssqlite3.pc\s(generated\sby\s'configure')\son\s'make\sdistclean',\stoo\s(CVS\s4290)
|
||||
D 2007-08-24T18:32:58
|
||||
C New\smutex\simplementation\sfor\sboth\sUnix\sand\swindows.\s(CVS\s4291)
|
||||
D 2007-08-24T20:46:59
|
||||
F Makefile.in 938f2769921fa1b30c633548f153804021eb1512
|
||||
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
|
||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||
@ -103,7 +103,7 @@ F src/malloc.c d4282f50964ab1ca31f504c97b7cf2fdb4d4195d
|
||||
F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
|
||||
F src/mem1.c afe2fbf6d7e8247c6c9f69c1481358b1cad60c08
|
||||
F src/mem2.c 1a2ca756a285b5365d667841508cc1f98938b8d8
|
||||
F src/mutex.c 9cf641f556a4119ef90ed41b82f2d5647f81686e
|
||||
F src/mutex.c 81ca843fedb51b614a9a31fe92c275bae0033be2
|
||||
F src/os.c a8ed3c495161475dbce255f7003144144fb425f1
|
||||
F src/os.h 2bfbbad126a775e4d8c7d59eb4d9585a5fd7dfb5
|
||||
F src/os_common.h a5c446d3b93f09f369d13bf217de4bed3437dd1c
|
||||
@ -561,7 +561,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||
P 75aad316981690d7a93ea6ac1c187f7d98f6d715
|
||||
R f6a11940cfa72ad9ecda6e5766c84640
|
||||
U rse
|
||||
Z 245dfea7d964a682d4ba69761182e105
|
||||
P 3c908648353a575c3ff57be5dd9454a946d23b9f
|
||||
R a4b1b44d66f0c9d1fa25ae7671bf0a2e
|
||||
U drh
|
||||
Z f2a9efc6afc9861301de6cbe6bd4d291
|
||||
|
@ -1 +1 @@
|
||||
3c908648353a575c3ff57be5dd9454a946d23b9f
|
||||
e144b81f699ca991cc4fa12a487156391db0b367
|
311
src/mutex.c
311
src/mutex.c
@ -12,7 +12,7 @@
|
||||
** This file contains the C functions that implement mutexes for
|
||||
** use by the SQLite core.
|
||||
**
|
||||
** $Id: mutex.c,v 1.8 2007/08/22 02:56:44 drh Exp $
|
||||
** $Id: mutex.c,v 1.9 2007/08/24 20:46:59 drh Exp $
|
||||
*/
|
||||
/*
|
||||
** If SQLITE_MUTEX_APPDEF is defined, then this whole module is
|
||||
@ -34,7 +34,6 @@
|
||||
# undef SQLITE_MUTEX_NOOP
|
||||
# define SQLITE_MUTEX_NOOP_DEBUG
|
||||
#endif
|
||||
#if 0
|
||||
#if defined(SQLITE_MUTEX_NOOP) && SQLITE_THREADSAFE && OS_UNIX
|
||||
# undef SQLITE_MUTEX_NOOP
|
||||
# define SQLITE_MUTEX_PTHREAD
|
||||
@ -43,7 +42,6 @@
|
||||
# undef SQLITE_MUTEX_NOOP
|
||||
# define SQLITE_MUTEX_WIN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -215,16 +213,181 @@ int sqlite3_mutex_notheld(sqlite3_mutex *p){
|
||||
** This implementation of mutexes is built using a version of pthreads that
|
||||
** does not have native support for recursive mutexes.
|
||||
*/
|
||||
#include <pthread.h>
|
||||
|
||||
/*
|
||||
** Each recursive mutex is an instance of the following structure.
|
||||
*/
|
||||
struct sqlite3_mutex {
|
||||
pthread_mutex_t mainMutex; /* Mutex controlling the lock */
|
||||
pthread_mutex_t auxMutex; /* Mutex controlling access to nRef and owner */
|
||||
int id; /* Mutex type */
|
||||
int nRef; /* Number of entrances */
|
||||
pthread_t owner; /* Thread that is within this mutex */
|
||||
pthread_mutex_t mutex; /* Mutex controlling the lock */
|
||||
int id; /* Mutex type */
|
||||
int nRef; /* Number of entrances */
|
||||
pthread_t owner; /* Thread that is within this mutex */
|
||||
};
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_alloc() routine allocates a new
|
||||
** mutex and returns a pointer to it. If it returns NULL
|
||||
** that means that a mutex could not be allocated. SQLite
|
||||
** will unwind its stack and return an error. The argument
|
||||
** to sqlite3_mutex_alloc() is one of these integer constants:
|
||||
**
|
||||
** <ul>
|
||||
** <li> SQLITE_MUTEX_FAST
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** </ul>
|
||||
**
|
||||
** The first two constants cause sqlite3_mutex_alloc() to create
|
||||
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
|
||||
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
|
||||
** The mutex implementation does not need to make a distinction
|
||||
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
|
||||
** not want to. But SQLite will only request a recursive mutex in
|
||||
** cases where it really needs one. If a faster non-recursive mutex
|
||||
** implementation is available on the host platform, the mutex subsystem
|
||||
** might return such a mutex in response to SQLITE_MUTEX_FAST.
|
||||
**
|
||||
** The other allowed parameters to sqlite3_mutex_alloc() each return
|
||||
** a pointer to a static preexisting mutex. Three static mutexes are
|
||||
** used by the current version of SQLite. Future versions of SQLite
|
||||
** may add additional static mutexes. Static mutexes are for internal
|
||||
** use by SQLite only. Applications that use SQLite mutexes should
|
||||
** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
|
||||
** SQLITE_MUTEX_RECURSIVE.
|
||||
**
|
||||
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
|
||||
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
|
||||
** returns a different mutex on every call. But for the static
|
||||
** mutex types, the same mutex is returned on every call that has
|
||||
** the same type number.
|
||||
*/
|
||||
sqlite3_mutex *sqlite3_mutex_alloc(int iType){
|
||||
static sqlite3_mutex staticMutexes[] = {
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
};
|
||||
sqlite3_mutex *p;
|
||||
switch( iType ){
|
||||
case SQLITE_MUTEX_FAST:
|
||||
case SQLITE_MUTEX_RECURSIVE: {
|
||||
p = sqlite3MallocZero( sizeof(*p) );
|
||||
if( p ){
|
||||
p->id = iType;
|
||||
pthread_mutex_init(&p->mutex, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert( iType-2 >= 0 );
|
||||
assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) );
|
||||
p = &staticMutexes[iType-2];
|
||||
p->id = iType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This routine deallocates a previously
|
||||
** allocated mutex. SQLite is careful to deallocate every
|
||||
** mutex that it allocates.
|
||||
*/
|
||||
void sqlite3_mutex_free(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
assert( p->nRef==0 );
|
||||
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
pthread_mutex_destroy(&p->mutex);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
|
||||
** to enter a mutex. If another thread is already within the mutex,
|
||||
** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
|
||||
** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
|
||||
** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
|
||||
** be entered multiple times by the same thread. In such cases the,
|
||||
** mutex must be exited an equal number of times before another thread
|
||||
** can enter. If the same thread tries to enter any other kind of mutex
|
||||
** more than once, the behavior is undefined.
|
||||
*/
|
||||
void sqlite3_mutex_enter(sqlite3_mutex *p){
|
||||
pthread_t self = pthread_self();
|
||||
if( pthread_equal(p->owner, self) && p->nRef>0 ){
|
||||
p->nRef++;
|
||||
}else{
|
||||
pthread_mutex_lock(&p->mutex);
|
||||
assert( p->nRef==0 );
|
||||
p->owner = self;
|
||||
p->nRef = 1;
|
||||
}
|
||||
}
|
||||
int sqlite3_mutex_try(sqlite3_mutex *p){
|
||||
pthread_t self = pthread_self();
|
||||
int rc;
|
||||
if( pthread_equal(p->owner, self) && p->nRef>0 ){
|
||||
p->nRef++;
|
||||
rc = SQLITE_OK;
|
||||
}else if( pthread_mutex_lock(&p->mutex)==0 ){
|
||||
assert( p->nRef==0 );
|
||||
p->owner = self;
|
||||
p->nRef = 1;
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = SQLITE_BUSY;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_leave() routine exits a mutex that was
|
||||
** previously entered by the same thread. The behavior
|
||||
** is undefined if the mutex is not currently entered or
|
||||
** is not currently allocated. SQLite will never do either.
|
||||
*/
|
||||
void sqlite3_mutex_leave(sqlite3_mutex *p){
|
||||
assert( pthread_equal(p->owner, pthread_self()) );
|
||||
assert( p->nRef>0 );
|
||||
p->nRef--;
|
||||
if( p->nRef==0 ){
|
||||
pthread_mutex_unlock(&p->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
|
||||
** intended for use inside assert() statements.
|
||||
*/
|
||||
int sqlite3_mutex_held(sqlite3_mutex *p){
|
||||
return p==0 || (p->nRef!=0 && pthread_equal(p->owner, pthread_self()));
|
||||
}
|
||||
int sqlite3_mutex_notheld(sqlite3_mutex *p){
|
||||
return p==0 || p->nRef==0 || pthread_equal(p->owner, pthread_self())==0;
|
||||
}
|
||||
#endif /* SQLITE_MUTEX_PTHREAD */
|
||||
|
||||
#ifdef SQLITE_MUTEX_WIN
|
||||
/********************** Windows Mutex Implementation **********************
|
||||
**
|
||||
** This implementation of mutexes is built using the win32 API.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Each recursive mutex is an instance of the following structure.
|
||||
*/
|
||||
struct sqlite3_mutex {
|
||||
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
|
||||
int id; /* Mutex type */
|
||||
int nRef; /* Number of enterances */
|
||||
DWORD owner; /* Thread holding this mutex */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -267,35 +430,35 @@ struct sqlite3_mutex {
|
||||
** the same type number.
|
||||
*/
|
||||
sqlite3_mutex *sqlite3_mutex_alloc(int iType){
|
||||
static sqlite3_mutex staticMutexes[] = {
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
{ PTHREAD_MUTEX_INITIALIZER, },
|
||||
};
|
||||
sqlite3_mutex *p;
|
||||
|
||||
switch( iType ){
|
||||
case SQLITE_MUTEX_FAST: {
|
||||
case SQLITE_MUTEX_FAST:
|
||||
case SQLITE_MUTEX_RECURSIVE: {
|
||||
p = sqlite3MallocZero( sizeof(*p) );
|
||||
if( p ){
|
||||
p->id = iType;
|
||||
pthread_mutex_init(&px->mainMutex, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_MUTEX_RECURSIVE: {
|
||||
p = sqlite3_malloc( sizeof(*p) );
|
||||
if( p ){
|
||||
px->id = iType;
|
||||
pthread_mutex_init(&px->auxMutex, 0);
|
||||
pthread_mutex_init(&px->mainMutex, 0);
|
||||
px->nRef = 0;
|
||||
InitializeCriticalSection(&p->mutex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
static sqlite3_mutex staticMutexes[4];
|
||||
static int isInit = 0;
|
||||
while( !isInit ){
|
||||
static long lock = 0;
|
||||
if( InterlockedIncrement(&lock)==1 ){
|
||||
int i;
|
||||
for(i=0; i<sizeof(staticMutexes)/sizeof(staticMutexes[0]); i++){
|
||||
InitializeCriticalSection(&staticMutexes[i].mutex);
|
||||
}
|
||||
isInit = 1;
|
||||
}else{
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
assert( iType-2 >= 0 );
|
||||
assert( iType-2 < count(staticMutexes) );
|
||||
assert( iType-2 < sizeof(staticMutexes)/sizeof(staticMutexes[0]) );
|
||||
p = &staticMutexes[iType-2];
|
||||
p->id = iType;
|
||||
break;
|
||||
@ -313,13 +476,8 @@ sqlite3_mutex *sqlite3_mutex_alloc(int iType){
|
||||
void sqlite3_mutex_free(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
assert( p->nRef==0 );
|
||||
if( p->id==SQLITE_MUTEX_FAST ){
|
||||
pthread_mutex_destroy(&p->mainMutex);
|
||||
}else{
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
pthread_mutex_destroy(&p->auxMutex);
|
||||
pthread_mutex_destroy(&p->mainMutex);
|
||||
}
|
||||
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
DeleteCriticalSection(&p->mutex);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
@ -335,54 +493,20 @@ void sqlite3_mutex_free(sqlite3_mutex *p){
|
||||
** more than once, the behavior is undefined.
|
||||
*/
|
||||
void sqlite3_mutex_enter(sqlite3_mutex *p){
|
||||
if( p->id==SQLITE_MUTEX_RECURSIVE ){
|
||||
while(1){
|
||||
pthread_mutex_lock(&p->auxMutex);
|
||||
if( p->nRef==0 ){
|
||||
p->nRef++;
|
||||
p->owner = pthread_self();
|
||||
pthread_mutex_lock(&p->mainMutex);
|
||||
pthread_mutex_unlock(&p->auxMutex);
|
||||
break;
|
||||
}else if( pthread_equal(p->owner, pthread_self()) ){
|
||||
p->nRef++;
|
||||
pthread_mutex_unlock(&p->auxMutex);
|
||||
break;
|
||||
}else{
|
||||
pthread_mutex_unlock(&p->auxMutex);
|
||||
pthread_mutex_lock(&p->mainMutex);
|
||||
pthread_mutex_unlock(&p->mainMutex);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
assert( p->nRef==0 || pthread_equal(p->owner, pthread_self())==0 );
|
||||
pthread_mutex_lock(&p->mutex);
|
||||
assert( (p->nRef = 1)!=0 );
|
||||
assert( (p->owner = pthread_self())==pthread_self() );
|
||||
}
|
||||
EnterCriticalSection(&p->mutex);
|
||||
p->owner = GetCurrentThreadId();
|
||||
p->nRef++;
|
||||
}
|
||||
int sqlite3_mutex_try(sqlite3_mutex *p){
|
||||
if( p->id==SQLITE_MUTEX_RECURSIVE ){
|
||||
pthread_mutex_lock(&p->auxMutex);
|
||||
if( p->nRef==0 ){
|
||||
p->nRef++;
|
||||
p->owner = pthread_self();
|
||||
pthread_mutex_lock(&p->mainMutex);
|
||||
pthread_mutex_unlock(&p->auxMutex);
|
||||
}else if( pthread_equal(p->owner, pthread_self()) ){
|
||||
p->nRef++;
|
||||
pthread_mutex_unlock(&p->auxMutex);
|
||||
}else{
|
||||
pthread_mutex_unlock(&p->auxMutex);
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
int rc;
|
||||
if( TryEnterCriticalSection(&p->mutex) ){
|
||||
p->owner = GetCurrentThreadId();
|
||||
p->nRef++;
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
assert( p->nRef==0 || pthread_equal(p->owner, pthread_self())==0 );
|
||||
if( pthread_mutex_trylock(&p->mutex) ){
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
rc = SQLITE_BUSY;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -391,22 +515,11 @@ int sqlite3_mutex_try(sqlite3_mutex *p){
|
||||
** is undefined if the mutex is not currently entered or
|
||||
** is not currently allocated. SQLite will never do either.
|
||||
*/
|
||||
void sqlite3_mutex_leave(sqlite3_mutex *pMutex){
|
||||
if( p->id==SQLITE_MUTEX_RECURSIVE ){
|
||||
pthread_mutex_lock(&p->auxMutex);
|
||||
assert( p->nRef>0 );
|
||||
assert( pthread_equal(p->owner, pthread_self()) );
|
||||
p->nRef--;
|
||||
if( p->nRef<=0 ){
|
||||
pthread_mutex_unlock(&p->mainMutex);
|
||||
}
|
||||
pthread_mutex_unlock(&p->auxMutex);
|
||||
}else{
|
||||
assert( p->nRef==1 );
|
||||
assert( pthread_equal(p->owner, pthread_self()) );
|
||||
p->nRef = 0;
|
||||
pthread_mutex_unlock(&p->mutex);
|
||||
}
|
||||
void sqlite3_mutex_leave(sqlite3_mutex *p){
|
||||
assert( p->nRef>0 );
|
||||
assert( p->owner==GetCurrentThreadId() );
|
||||
p->nRef--;
|
||||
LeaveCriticalSection(&p->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -414,13 +527,11 @@ void sqlite3_mutex_leave(sqlite3_mutex *pMutex){
|
||||
** intended for use inside assert() statements.
|
||||
*/
|
||||
int sqlite3_mutex_held(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
return p==0 || (p->nRef!=0 && pthread_equal(p->owner, pthread_self()));
|
||||
return p==0 || (p->nRef!=0 && p->owner==GetCurrentThreadId());
|
||||
}
|
||||
int sqlite3_mutex_notheld(sqlite3_mutex *pNotUsed){
|
||||
assert( p );
|
||||
return p==0 || p->nRef==0 || pthread_equal(p->owner, pthread_self())==0;
|
||||
int sqlite3_mutex_notheld(sqlite3_mutex *p){
|
||||
return p==0 || p->nRef==0 || p->owner!=GetCurrentThreadId();
|
||||
}
|
||||
#endif /* SQLITE_MUTEX_PTHREAD */
|
||||
#endif /* SQLITE_MUTEX_WIN */
|
||||
|
||||
#endif /* !defined(SQLITE_MUTEX_APPDEF) */
|
||||
|
Loading…
x
Reference in New Issue
Block a user