Use read/write locking on Windows
authorVincent Drake <vdrake@gmail.com>
Mon, 1 Mar 2021 19:38:02 +0000 (14:38 -0500)
committerMatt Caswell <matt@openssl.org>
Thu, 11 Mar 2021 10:33:06 +0000 (10:33 +0000)
Fixes #13914

The "SRWLock" synchronization primitive is available in Windows Vista
and later.  CRYPTO_THREAD functions now use SRWLock functions when the
target operating system supports them.

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14381)

CHANGES.md
crypto/threads_win.c

index a547b40829c21c36c44088f67dc908ee0a77b242..bdac54c10fe0e0ad3ed551368980b2a169cb951c 100644 (file)
@@ -23,6 +23,11 @@ OpenSSL 3.0
 
 ### Changes between 1.1.1 and 3.0 [xx XXX xxxx]
 
+ * Windows thread synchronization uses read/write primitives (SRWLock) when
+   supported by the OS, otherwise CriticalSection continues to be used.
+
+   *Vincent Drake*
+
  * Add filter BIO BIO_f_readbuffer() that allows BIO_tell() and BIO_seek() to
    work on read only BIO source/sinks that do not support these functions.
    This allows piping or redirection of a file BIO using stdin to be buffered
index ef68fe2d24a3b5eaa40727a284db76da76528fe0..34c8964aa616bf4918e6e2d7d4668d99095c09e7 100644 (file)
@@ -9,29 +9,49 @@
 
 #if defined(_WIN32)
 # include <windows.h>
+# if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
+#  include <synchapi.h>
+#  define USE_RWLOCK
+# endif
 #endif
 
 #include <openssl/crypto.h>
 
 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && defined(OPENSSL_SYS_WINDOWS)
 
+# ifdef USE_RWLOCK
+typedef struct {
+    SRWLOCK lock;
+    int exclusive;
+} CRYPTO_win_rwlock;
+# endif
+
 CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
 {
     CRYPTO_RWLOCK *lock;
+# ifdef USE_RWLOCK
+    CRYPTO_win_rwlock *rwlock;
+
+    if ((lock = OPENSSL_zalloc(sizeof(CRYPTO_win_rwlock))) == NULL)
+        return NULL;
+    rwlock = lock;
+    InitializeSRWLock(&rwlock->lock);
+# else
 
     if ((lock = OPENSSL_zalloc(sizeof(CRITICAL_SECTION))) == NULL) {
         /* Don't set error, to avoid recursion blowup. */
         return NULL;
     }
 
-# if !defined(_WIN32_WCE)
+#  if !defined(_WIN32_WCE)
     /* 0x400 is the spin count value suggested in the documentation */
     if (!InitializeCriticalSectionAndSpinCount(lock, 0x400)) {
         OPENSSL_free(lock);
         return NULL;
     }
-# else
+#  else
     InitializeCriticalSection(lock);
+#  endif
 # endif
 
     return lock;
@@ -39,19 +59,43 @@ CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
 
 int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
 {
+# ifdef USE_RWLOCK
+    CRYPTO_win_rwlock *rwlock = lock;
+
+    AcquireSRWLockShared(&rwlock->lock);
+# else
     EnterCriticalSection(lock);
+# endif
     return 1;
 }
 
 int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
 {
+# ifdef USE_RWLOCK
+    CRYPTO_win_rwlock *rwlock = lock;
+
+    AcquireSRWLockExclusive(&rwlock->lock);
+    rwlock->exclusive = 1;
+# else
     EnterCriticalSection(lock);
+# endif
     return 1;
 }
 
 int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
 {
+# ifdef USE_RWLOCK
+    CRYPTO_win_rwlock *rwlock = lock;
+
+    if (rwlock->exclusive) {
+        rwlock->exclusive = 0;
+        ReleaseSRWLockExclusive(&rwlock->lock);
+    } else {
+        ReleaseSRWLockShared(&rwlock->lock);
+    }
+# else
     LeaveCriticalSection(lock);
+# endif
     return 1;
 }
 
@@ -60,7 +104,9 @@ void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
     if (lock == NULL)
         return;
 
+# ifndef USE_RWLOCK
     DeleteCriticalSection(lock);
+# endif
     OPENSSL_free(lock);
 
     return;