]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
New mutex implementation for both Unix and windows. (CVS 4291)
authordrh <drh@noemail.net>
Fri, 24 Aug 2007 20:46:59 +0000 (20:46 +0000)
committerdrh <drh@noemail.net>
Fri, 24 Aug 2007 20:46:59 +0000 (20:46 +0000)
FossilOrigin-Name: e144b81f699ca991cc4fa12a487156391db0b367

manifest
manifest.uuid
src/mutex.c

index 31be35e2252dbdb5d8ccb1dfdf94a2d52bb09d6b..ff5a0c5667992d4fd7356a86675675930a28c883 100644 (file)
--- 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
index 8fd5b66fd1ed68ad25e26a521c0aaf37124ac64a..bbcf7ed766b0d8784f65d927fb3019eb62aa4341 100644 (file)
@@ -1 +1 @@
-3c908648353a575c3ff57be5dd9454a946d23b9f
\ No newline at end of file
+e144b81f699ca991cc4fa12a487156391db0b367
\ No newline at end of file
index bbcaf22272780670907e858143c8b796d3945cdc..38caf94fb8673881f42ac440ed1b7bd8c32fccb6 100644 (file)
@@ -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,16 @@ 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 */
 };
 
 /*
@@ -235,11 +233,12 @@ struct sqlite3_mutex {
 ** to sqlite3_mutex_alloc() is one of these integer constants:
 **
 ** <ul>
-** <li>  SQLITE_MUTEX_FAST               0
-** <li>  SQLITE_MUTEX_RECURSIVE          1
-** <li>  SQLITE_MUTEX_STATIC_MASTER      2
-** <li>  SQLITE_MUTEX_STATIC_MEM         3
-** <li>  SQLITE_MUTEX_STATIC_PRNG        4
+** <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
@@ -275,27 +274,18 @@ sqlite3_mutex *sqlite3_mutex_alloc(int iType){
   };
   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;
+        pthread_mutex_init(&p->mutex, 0);
       }
       break;
     }
     default: {
       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 +303,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 );
+  pthread_mutex_destroy(&p->mutex);
   sqlite3_free(p);
 }
 
@@ -335,54 +320,31 @@ 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);
-      }
-    }
+  pthread_t self = pthread_self();
+  if( pthread_equal(p->owner, self) && p->nRef>0 ){
+    p->nRef++;
   }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() );
+    assert( p->nRef==0 );
+    p->owner = self;
+    p->nRef = 1;
   }
 }
 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;
-    }
+  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{
-    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,20 +353,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;
+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);
   }
 }
@@ -414,13 +367,171 @@ 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()));
 }
-int sqlite3_mutex_notheld(sqlite3_mutex *pNotUsed){
-  assert( p );
+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 */
+};
+
+/*
+** 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               0
+** <li>  SQLITE_MUTEX_RECURSIVE          1
+** <li>  SQLITE_MUTEX_STATIC_MASTER      2
+** <li>  SQLITE_MUTEX_STATIC_MEM         3
+** <li>  SQLITE_MUTEX_STATIC_PRNG        4
+** </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){
+  sqlite3_mutex *p;
+
+  switch( iType ){
+    case SQLITE_MUTEX_FAST:
+    case SQLITE_MUTEX_RECURSIVE: {
+      p = sqlite3MallocZero( sizeof(*p) );
+      if( p ){
+        p->id = iType;
+        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 < 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 );
+  DeleteCriticalSection(&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){
+  EnterCriticalSection(&p->mutex);
+  p->owner = GetCurrentThreadId(); 
+  p->nRef++;
+}
+int sqlite3_mutex_try(sqlite3_mutex *p){
+  int rc;
+  if( TryEnterCriticalSection(&p->mutex) ){
+    p->owner = GetCurrentThreadId();
+    p->nRef++;
+    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( p->nRef>0 );
+  assert( p->owner==GetCurrentThreadId() );
+  p->nRef--;
+  LeaveCriticalSection(&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 && p->owner==GetCurrentThreadId());
+}
+int sqlite3_mutex_notheld(sqlite3_mutex *p){
+  return p==0 || p->nRef==0 || p->owner!=GetCurrentThreadId();
+}
+#endif /* SQLITE_MUTEX_WIN */
+
 #endif /* !defined(SQLITE_MUTEX_APPDEF) */