]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Updates and simplifications to the mutex implementation on Windows. Uses win-mutex-revamp
authordrh <>
Tue, 28 Apr 2026 20:01:03 +0000 (20:01 +0000)
committerdrh <>
Tue, 28 Apr 2026 20:01:03 +0000 (20:01 +0000)
Slim Reader/Writer Locks for performance, for non-reentrant mutexes.
Requires WindowsVista or later.

FossilOrigin-Name: a75aa5400f94531b8ffd00be4580b0578d8d81ba9681fd06b1d9d96a6180994c

manifest
manifest.tags
manifest.uuid
src/mutex_w32.c

index a04e53a9b57a6b39478bb105ccf93badbbc1f32e..eb22c21d1bf9df839aa7e59a8b76e05bfc426493 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Attempt\sto\salign\sinstances\sof\sthe\ssqlite3_mutex\sobject\sat\s128-byte\sboundaries\nto\sprevent\sfalse-sharing\sin\smulti-core\smachines.\sSee\sthe\sdiscussion\sat\sand\naround\s[forum:/forumpost/2026-03-25T23:15:03Z|forum\spost\s2026-03-25T23:15:03Z].
-D 2026-04-28T15:12:40.363
+C Updates\sand\ssimplifications\sto\sthe\smutex\simplementation\son\sWindows.\s\sUses\nSlim\sReader/Writer\sLocks\sfor\sperformance,\sfor\snon-reentrant\smutexes.\nRequires\sWindowsVista\sor\slater.
+D 2026-04-28T20:01:03.205
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -713,7 +713,7 @@ F src/mutex.c 00b8cee206a67fd764d001f3a148494331d8d0b3b9c3974ecd69ff29bb444462
 F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a
 F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
 F src/mutex_unix.c 9dce885059f9d2bb226e6e03bb2b41af4b89d40c323f908b58f5d05ff0565884
-F src/mutex_w32.c cd49a5772f1bfd174e22a0c783ba514a871a3a7089f90d7337019c32fecca94b
+F src/mutex_w32.c 6eb3fc28172d267c4a6a92ef09f557ac8bcebc01ac5638a2bb528c492011dff6
 F src/notify.c 57c2d1a2805d6dee32acd5d250d928ab94e02d76369ae057dee7d445fd64e878
 F src/os.c 509452169d5ea739723e213b8e2481cf0e587f0e88579a912d200db5269f5f6d
 F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
@@ -2203,8 +2203,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P d64a1dbe0fb2d9286806d833a3146b21d5bf1636a650d5a64cf163c7f2356e98
-R e7f5576deb3afe7b12491989f716c8e2
+P 1786fcd5b4ee6cd9b4780f3687dfaec5b90ef0476e0da266a94e069b98e70514
+R 86e1ad059a85bf06401a6419341a6e82
+T *branch * win-mutex-revamp
+T *sym-win-mutex-revamp *
+T -sym-trunk *
 U drh
-Z 8f2b29d8666e7ca0a228448a291e99d6
+Z 2cf5e98ef789e1ee6f49efcdd7196e10
 # Remove this line to create a well-formed Fossil manifest.
index bec971799ff1b8ee641c166c7aeb22d12c785393..3424048c520f0c9623208811029a218e939403fb 100644 (file)
@@ -1,2 +1,2 @@
-branch trunk
-tag trunk
+branch win-mutex-revamp
+tag win-mutex-revamp
index 33b63b5768bc0eb94215e6bcd58663f692bc19e3..c25a81020a9a2b94698d319518cc5cf81a71f3c9 100644 (file)
@@ -1 +1 @@
-1786fcd5b4ee6cd9b4780f3687dfaec5b90ef0476e0da266a94e069b98e70514
+a75aa5400f94531b8ffd00be4580b0578d8d81ba9681fd06b1d9d96a6180994c
index a888e241006b89723c3f41f5126e43299809f760..3fef1f8be47ff3af5fe50721be56d9b8d664c4b7 100644 (file)
@@ -37,6 +37,8 @@
 # define ALIGN128
 #endif
 
+#pragma warning(push)
+#pragma warning(disable: 4324)
 /*
 ** Each SQLite mutex is an instance of the following structure.
 **
 ** that 64 works just as well most of the time, but the internet says
 ** that 128-byte alignment works better.
 */
-struct ALIGN128 sqlite3_mutex {
-  CRITICAL_SECTION mutex;    /* Mutex controlling the lock */
+struct ALIGN128 sqlite3_mutex { 
+  union {
+    CRITICAL_SECTION cs;     /* The CRITICAL_SECTION mutex.  id==1 */
+    SRWLOCK srwl;            /* The Slim reader/writer lock.  id!=1 */
+  } u;
   int id;                    /* Mutex type */
 #ifdef SQLITE_DEBUG
   volatile int nRef;         /* Number of entrances */
@@ -56,20 +61,7 @@ struct ALIGN128 sqlite3_mutex {
   volatile LONG trace;       /* True to trace changes */
 #endif
 };
-
-/*
-** These are the initializer values used when declaring a "static" mutex
-** on Win32.  It should be noted that all mutexes require initialization
-** on the Win32 platform.
-*/
-#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
-
-#ifdef SQLITE_DEBUG
-#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id, \
-                                    0L, (DWORD)0, 0 }
-#else
-#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id }
-#endif
+#pragma warning(pop)
 
 #ifdef SQLITE_DEBUG
 /*
@@ -80,13 +72,8 @@ static int winMutexHeld(sqlite3_mutex *p){
   return p->nRef!=0 && p->owner==GetCurrentThreadId();
 }
 
-static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){
-  return p->nRef==0 || p->owner!=tid;
-}
-
 static int winMutexNotheld(sqlite3_mutex *p){
-  DWORD tid = GetCurrentThreadId();
-  return winMutexNotheld2(p, tid);
+  return p->nRef==0 || p->owner!=GetCurrentThreadId();
 }
 #endif
 
@@ -110,23 +97,8 @@ void sqlite3MemoryBarrier(void){
 /*
 ** Initialize and deinitialize the mutex subsystem.
 */
-static sqlite3_mutex winMutex_staticMutexes[] = {
-  SQLITE3_MUTEX_INITIALIZER(2),
-  SQLITE3_MUTEX_INITIALIZER(3),
-  SQLITE3_MUTEX_INITIALIZER(4),
-  SQLITE3_MUTEX_INITIALIZER(5),
-  SQLITE3_MUTEX_INITIALIZER(6),
-  SQLITE3_MUTEX_INITIALIZER(7),
-  SQLITE3_MUTEX_INITIALIZER(8),
-  SQLITE3_MUTEX_INITIALIZER(9),
-  SQLITE3_MUTEX_INITIALIZER(10),
-  SQLITE3_MUTEX_INITIALIZER(11),
-  SQLITE3_MUTEX_INITIALIZER(12),
-  SQLITE3_MUTEX_INITIALIZER(13)
-};
-
+static sqlite3_mutex winMutex_staticMutexes[12];
 static int winMutex_isInit = 0;
-static int winMutex_isNt = -1; /* <0 means "need to query" */
 
 /* As the winMutexInit() and winMutexEnd() functions are called as part
 ** of the sqlite3_initialize() and sqlite3_shutdown() processing, the
@@ -142,7 +114,14 @@ static int winMutexInit(void){
   if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){
     int i;
     for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
-      InitializeCriticalSection(&winMutex_staticMutexes[i].mutex);
+      sqlite3_mutex *p = &winMutex_staticMutexes[i];
+      p->id = i+2;
+      InitializeSRWLock(&p->u.srwl);
+#ifdef SQLITE_DEBUG
+      p->nRef = 0;
+      p->owner = 0;
+      p->trace = 0;
+#endif
     }
     winMutex_isInit = 1;
   }else{
@@ -160,10 +139,6 @@ static int winMutexEnd(void){
   ** (which should be the last to shutdown.) */
   if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){
     if( winMutex_isInit==1 ){
-      int i;
-      for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
-        DeleteCriticalSection(&winMutex_staticMutexes[i].mutex);
-      }
       winMutex_isInit = 0;
     }
   }
@@ -232,7 +207,11 @@ static sqlite3_mutex *winMutexAlloc(int iType){
         p->trace = 1;
 #endif
 #endif
-        InitializeCriticalSection(&p->mutex);
+        if( iType==SQLITE_MUTEX_RECURSIVE ){
+          InitializeCriticalSection(&p->u.cs);
+        }else{
+          InitializeSRWLock(&p->u.srwl);
+        }
       }
       break;
     }
@@ -265,8 +244,10 @@ static sqlite3_mutex *winMutexAlloc(int iType){
 static void winMutexFree(sqlite3_mutex *p){
   assert( p );
   assert( p->nRef==0 && p->owner==0 );
-  if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){
-    DeleteCriticalSection(&p->mutex);
+  if( p->id==SQLITE_MUTEX_FAST ){
+    sqlite3_free(p);
+  }else if( p->id==SQLITE_MUTEX_RECURSIVE ){
+    DeleteCriticalSection(&p->u.cs);
     sqlite3_free(p);
   }else{
 #ifdef SQLITE_ENABLE_API_ARMOR
@@ -287,67 +268,56 @@ static void winMutexFree(sqlite3_mutex *p){
 ** more than once, the behavior is undefined.
 */
 static void winMutexEnter(sqlite3_mutex *p){
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
-  DWORD tid = GetCurrentThreadId();
-#endif
-#ifdef SQLITE_DEBUG
-  assert( p );
-  assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
-#else
   assert( p );
+#ifdef SQLITE_DEBUG
+  assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
 #endif
   assert( winMutex_isInit==1 );
-  EnterCriticalSection(&p->mutex);
+  if( p->id==SQLITE_MUTEX_RECURSIVE ){
+    EnterCriticalSection(&p->u.cs);
+  }else{
+    AcquireSRWLockExclusive(&p->u.srwl);
+  }
 #ifdef SQLITE_DEBUG
   assert( p->nRef>0 || p->owner==0 );
-  p->owner = tid;
+  p->owner = GetCurrentThreadId();
   p->nRef++;
   if( p->trace ){
     OSTRACE(("ENTER-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",
-             tid, p->id, p, p->trace, p->nRef));
+             GetCurrentThreadId(), p->id, p, p->trace, p->nRef));
   }
 #endif
 }
 
 static int winMutexTry(sqlite3_mutex *p){
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
-  DWORD tid = GetCurrentThreadId();
-#endif
   int rc = SQLITE_BUSY;
   assert( p );
-  assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
+  assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
   /*
-  ** The sqlite3_mutex_try() routine is very rarely used, and when it
-  ** is used it is merely an optimization.  So it is OK for it to always
+  ** The sqlite3_mutex_try() routine is seldom used, and when it is
+  ** used it is merely an optimization.  So it is OK for it to always
   ** fail.
-  **
-  ** The TryEnterCriticalSection() interface is only available on WinNT.
-  ** And some windows compilers complain if you try to use it without
-  ** first doing some #defines that prevent SQLite from building on Win98.
-  ** For that reason, we will omit this optimization for now.  See
-  ** ticket #2685.
   */
-#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400
-  assert( winMutex_isInit==1 );
-  assert( winMutex_isNt>=-1 && winMutex_isNt<=1 );
-  if( winMutex_isNt<0 ){
-    winMutex_isNt = sqlite3_win32_is_nt();
+  if( p->id==SQLITE_MUTEX_RECURSIVE ){
+    rc = TryEnterCriticalSection(&p->u.cs);
+  }else{
+    rc = TryAcquireSRWLockExclusive(&p->u.srwl);
   }
-  assert( winMutex_isNt==0 || winMutex_isNt==1 );
-  if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){
+  if( rc ){
 #ifdef SQLITE_DEBUG
-    p->owner = tid;
+    p->owner = GetCurrentThreadId();
     p->nRef++;
 #endif
     rc = SQLITE_OK;
+  }else{
+    rc = SQLITE_BUSY;
   }
-#else
-  UNUSED_PARAMETER(p);
-#endif
 #ifdef SQLITE_DEBUG
   if( p->trace ){
-    OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
-             tid, p->id, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc)));
+    OSTRACE((
+       "TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
+       GetCurrentThreadId(), p->id, p, p->trace, p->owner, p->nRef,
+       sqlite3ErrName(rc)));
   }
 #endif
   return rc;
@@ -360,23 +330,24 @@ static int winMutexTry(sqlite3_mutex *p){
 ** is not currently allocated.  SQLite will never do either.
 */
 static void winMutexLeave(sqlite3_mutex *p){
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
-  DWORD tid = GetCurrentThreadId();
-#endif
   assert( p );
 #ifdef SQLITE_DEBUG
   assert( p->nRef>0 );
-  assert( p->owner==tid );
+  assert( p->owner==GetCurrentThreadId() );
   p->nRef--;
   if( p->nRef==0 ) p->owner = 0;
   assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
 #endif
   assert( winMutex_isInit==1 );
-  LeaveCriticalSection(&p->mutex);
+  if( p->id==SQLITE_MUTEX_RECURSIVE ){
+    LeaveCriticalSection(&p->u.cs);
+  }else{
+    ReleaseSRWLockExclusive(&p->u.srwl);
+  }
 #ifdef SQLITE_DEBUG
   if( p->trace ){
     OSTRACE(("LEAVE-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",
-             tid, p->id, p, p->trace, p->nRef));
+             GetCurrentThreadId(), p->id, p, p->trace, p->nRef));
   }
 #endif
 }