diff options
Diffstat (limited to 'crypto/thread_win.c')
-rw-r--r-- | crypto/thread_win.c | 119 |
1 files changed, 36 insertions, 83 deletions
diff --git a/crypto/thread_win.c b/crypto/thread_win.c index e48ab5f5..c7a90f7e 100644 --- a/crypto/thread_win.c +++ b/crypto/thread_win.c @@ -16,11 +16,10 @@ #if defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS) -#pragma warning(push, 3) +OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include <windows.h> -#pragma warning(pop) +OPENSSL_MSVC_PRAGMA(warning(pop)) -#include <assert.h> #include <stdlib.h> #include <string.h> @@ -28,110 +27,59 @@ #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); -union run_once_arg_t { - void (*func)(void); - void *data; -}; - -static void run_once(CRYPTO_once_t *once, void (*init)(union run_once_arg_t), - union run_once_arg_t arg) { - /* Values must be aligned. */ - assert((((uintptr_t) once) & 3) == 0); - - /* This assumes that reading *once has acquire semantics. This should be true - * on x86 and x86-64, where we expect Windows to run. */ -#if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) -#error "Windows once code may not work on other platforms." \ - "You can use InitOnceBeginInitialize on >=Vista" -#endif - if (*once == 1) { - return; - } - - for (;;) { - switch (InterlockedCompareExchange(once, 2, 0)) { - case 0: - /* The value was zero so we are the first thread to call |CRYPTO_once| - * on it. */ - init(arg); - /* Write one to indicate that initialisation is complete. */ - InterlockedExchange(once, 1); - return; - - case 1: - /* Another thread completed initialisation between our fast-path check - * and |InterlockedCompareExchange|. */ - return; - - case 2: - /* Another thread is running the initialisation. Switch to it then try - * again. */ - SwitchToThread(); - break; - - default: - abort(); - } - } -} - -static void call_once_init(union run_once_arg_t arg) { - arg.func(); +static BOOL CALLBACK call_once_init(INIT_ONCE *once, void *arg, void **out) { + void (**init)(void) = (void (**)(void))arg; + (**init)(); + return TRUE; } -void CRYPTO_once(CRYPTO_once_t *in_once, void (*init)(void)) { - union run_once_arg_t arg; - arg.func = init; - run_once(in_once, call_once_init, arg); +void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) { + if (!InitOnceExecuteOnce(once, call_once_init, &init, NULL)) { + abort(); + } } 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(CRYPTO_MUTEX *lock) { - LeaveCriticalSection((CRITICAL_SECTION *) lock); +void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock) { + ReleaseSRWLockShared((SRWLOCK *) lock); } -void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { - DeleteCriticalSection((CRITICAL_SECTION *) lock); +void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock) { + ReleaseSRWLockExclusive((SRWLOCK *) lock); } -static void static_lock_init(union run_once_arg_t arg) { - struct CRYPTO_STATIC_MUTEX *lock = arg.data; - if (!InitializeCriticalSectionAndSpinCount(&lock->lock, 0x400)) { - abort(); - } +void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { + /* SRWLOCKs require no cleanup. */ } void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) { - union run_once_arg_t arg; - arg.data = lock; - /* Since we have to support Windows XP, read locks are actually exclusive. */ - run_once(&lock->once, static_lock_init, arg); - 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) { + ReleaseSRWLockShared(&lock->lock); } -void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) { - LeaveCriticalSection(&lock->lock); +void CRYPTO_STATIC_MUTEX_unlock_write(struct CRYPTO_STATIC_MUTEX *lock) { + ReleaseSRWLockExclusive(&lock->lock); } static CRITICAL_SECTION g_destructors_lock; @@ -150,9 +98,14 @@ static void thread_local_init(void) { g_thread_local_failed = (g_thread_local_key == TLS_OUT_OF_INDEXES); } -static void NTAPI thread_local_destructor(PVOID module, - DWORD reason, PVOID reserved) { - if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason) { +static void NTAPI thread_local_destructor(PVOID module, DWORD reason, + PVOID reserved) { + /* Only free memory on |DLL_THREAD_DETACH|, not |DLL_PROCESS_DETACH|. In + * VS2015's debug runtime, the C runtime has been unloaded by the time + * |DLL_PROCESS_DETACH| runs. See https://crbug.com/575795. This is consistent + * with |pthread_key_create| which does not call destructors on process exit, + * only thread exit. */ + if (reason != DLL_THREAD_DETACH) { return; } |