diff --git a/manifest b/manifest index 31be35e225..ff5a0c5667 100644 --- a/manifest +++ b/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 diff --git a/manifest.uuid b/manifest.uuid index 8fd5b66fd1..bbcf7ed766 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3c908648353a575c3ff57be5dd9454a946d23b9f \ No newline at end of file +e144b81f699ca991cc4fa12a487156391db0b367 \ No newline at end of file diff --git a/src/mutex.c b/src/mutex.c index bbcaf22272..38caf94fb8 100644 --- a/src/mutex.c +++ b/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 /* ** 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: +** +** +** +** 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= 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) */