Switch Windows CRYPTO_MUTEX implementation to SRWLOCK.

Now that we no longer support Windows XP, this is available.
Unfortunately, the public header version of CRYPTO_MUTEX means we
still can't easily merge CRYPTO_MUTEX and CRYPTO_STATIC_MUTEX.

BUG=37

Change-Id: If309de3f06e0854c505083b72fd64d1dbb3f4563
Reviewed-on: https://boringssl-review.googlesource.com/8081
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/internal.h b/crypto/internal.h
index 2d130fc..433072c 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -355,12 +355,8 @@
  * |CRYPTO_STATIC_MUTEX_INIT|.
  *
  * |CRYPTO_MUTEX| can appear in public structures and so is defined in
- * thread.h.
- *
- * The global lock is a different type because there's no static initialiser
- * value on Windows for locks, so global locks have to be coupled with a
- * |CRYPTO_once_t| to ensure that the lock is setup before use. This is done
- * automatically by |CRYPTO_STATIC_MUTEX_lock_*|. */
+ * thread.h as a structure large enough to fit the real type. The global lock is
+ * a different type so it may be initialized with platform initializer macros.*/
 
 #if defined(OPENSSL_NO_THREADS)
 struct CRYPTO_STATIC_MUTEX {
@@ -369,10 +365,9 @@
 #define CRYPTO_STATIC_MUTEX_INIT { 0 }
 #elif defined(OPENSSL_WINDOWS)
 struct CRYPTO_STATIC_MUTEX {
-  CRYPTO_once_t once;
-  CRITICAL_SECTION lock;
+  SRWLOCK lock;
 };
-#define CRYPTO_STATIC_MUTEX_INIT { CRYPTO_ONCE_INIT, { 0 } }
+#define CRYPTO_STATIC_MUTEX_INIT { SRWLOCK_INIT }
 #else
 struct CRYPTO_STATIC_MUTEX {
   pthread_rwlock_t lock;
@@ -385,8 +380,7 @@
 OPENSSL_EXPORT void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock);
 
 /* CRYPTO_MUTEX_lock_read locks |lock| such that other threads may also have a
- * read lock, but none may have a write lock. (On Windows, read locks are
- * actually fully exclusive.) */
+ * read lock, but none may have a write lock. */
 OPENSSL_EXPORT void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock);
 
 /* CRYPTO_MUTEX_lock_write locks |lock| such that no other thread has any type
diff --git a/crypto/thread_win.c b/crypto/thread_win.c
index 85e5993..9f7d82b 100644
--- a/crypto/thread_win.c
+++ b/crypto/thread_win.c
@@ -27,7 +27,7 @@
 #include <openssl/type_check.h>
 
 
-OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(CRITICAL_SECTION),
+OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(SRWLOCK),
                        CRYPTO_MUTEX_too_small);
 
 static BOOL CALLBACK call_once_init(INIT_ONCE *once, void *arg, void **out) {
@@ -43,60 +43,43 @@
 }
 
 void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) {
-  if (!InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *) lock, 0x400)) {
-    abort();
-  }
+  InitializeSRWLock((SRWLOCK *) lock);
 }
 
 void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) {
-  /* Since we have to support Windows XP, read locks are actually exclusive. */
-  EnterCriticalSection((CRITICAL_SECTION *) lock);
+  AcquireSRWLockShared((SRWLOCK *) lock);
 }
 
 void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) {
-  EnterCriticalSection((CRITICAL_SECTION *) lock);
+  AcquireSRWLockExclusive((SRWLOCK *) lock);
 }
 
 void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock) {
-  LeaveCriticalSection((CRITICAL_SECTION *) lock);
+  ReleaseSRWLockShared((SRWLOCK *) lock);
 }
 
 void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock) {
-  LeaveCriticalSection((CRITICAL_SECTION *) lock);
+  ReleaseSRWLockExclusive((SRWLOCK *) lock);
 }
 
 void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) {
-  DeleteCriticalSection((CRITICAL_SECTION *) lock);
-}
-
-static BOOL CALLBACK static_lock_init(INIT_ONCE *once, void *arg, void **out) {
-  struct CRYPTO_STATIC_MUTEX *lock = arg;
-  if (!InitializeCriticalSectionAndSpinCount(&lock->lock, 0x400)) {
-    abort();
-  }
-  return TRUE;
+  /* SRWLOCKs require no cleanup. */
 }
 
 void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) {
-  /* TODO(davidben): Consider replacing these with SRWLOCK now that we no longer
-   * need to support Windows XP. Currently, read locks are actually
-   * exclusive. */
-  if (!InitOnceExecuteOnce(&lock->once, static_lock_init, lock, NULL)) {
-    abort();
-  }
-  EnterCriticalSection(&lock->lock);
+  AcquireSRWLockShared(&lock->lock);
 }
 
 void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) {
-  CRYPTO_STATIC_MUTEX_lock_read(lock);
+  AcquireSRWLockExclusive(&lock->lock);
 }
 
 void CRYPTO_STATIC_MUTEX_unlock_read(struct CRYPTO_STATIC_MUTEX *lock) {
-  LeaveCriticalSection(&lock->lock);
+  ReleaseSRWLockShared(&lock->lock);
 }
 
 void CRYPTO_STATIC_MUTEX_unlock_write(struct CRYPTO_STATIC_MUTEX *lock) {
-  LeaveCriticalSection(&lock->lock);
+  ReleaseSRWLockExclusive(&lock->lock);
 }
 
 static CRITICAL_SECTION g_destructors_lock;
diff --git a/include/openssl/thread.h b/include/openssl/thread.h
index ac4ced0..02539e8 100644
--- a/include/openssl/thread.h
+++ b/include/openssl/thread.h
@@ -73,10 +73,9 @@
 #elif defined(OPENSSL_WINDOWS)
 /* CRYPTO_MUTEX can appear in public header files so we really don't want to
  * pull in windows.h. It's statically asserted that this structure is large
- * enough to contain a Windows CRITICAL_SECTION by thread_win.c. */
+ * enough to contain a Windows SRWLOCK by thread_win.c. */
 typedef union crypto_mutex_st {
-  double alignment;
-  uint8_t padding[4*sizeof(void*) + 2*sizeof(int)];
+  void *handle;
 } CRYPTO_MUTEX;
 #elif defined(__MACH__) && defined(__APPLE__)
 typedef pthread_rwlock_t CRYPTO_MUTEX;