From 02bcd7d5adb4b065ed1d663fc86a113ceb4ce533 Mon Sep 17 00:00:00 2001 From: Justin Smith Date: Mon, 15 Apr 2024 13:51:38 -0400 Subject: [PATCH] Retry for mingw statically initialized rwlocks --- crypto/thread_pthread.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/crypto/thread_pthread.c b/crypto/thread_pthread.c index c789292b46..3d36e3d09d 100644 --- a/crypto/thread_pthread.c +++ b/crypto/thread_pthread.c @@ -14,6 +14,8 @@ // Ensure we can't call OPENSSL_malloc circularly. #define _BORINGSSL_PROHIBIT_OPENSSL_MALLOC +#include + #include "internal.h" #if defined(OPENSSL_PTHREADS) @@ -64,14 +66,46 @@ void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { pthread_rwlock_destroy((pthread_rwlock_t *) lock); } +#ifdef __MINGW32__ +// Some MinGW pthreads implementations might fail on first use of +// locks initialized using PTHREAD_RWLOCK_INITIALIZER. +// See: https://sourceforge.net/p/mingw-w64/bugs/883/ +typedef int (*pthread_rwlock_func_ptr)(pthread_rwlock_t *); +static int rwlock_EINVAL_fallback_retry(const pthread_rwlock_func_ptr func_ptr, pthread_rwlock_t* lock) { + int result = EINVAL; + const int MAX_ATTEMPTS = 10; + int attempt_num = 0; + do { + sched_yield(); + attempt_num += 1; + result = func_ptr(lock); + } while(result == EINVAL && attempt_num < MAX_ATTEMPTS); + return result; +} +#endif + void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) { - if (pthread_rwlock_rdlock(&lock->lock) != 0) { + const int result = pthread_rwlock_rdlock(&lock->lock); + if (result != 0) { +#ifdef __MINGW32__ + if (result == EINVAL && + 0 == rwlock_EINVAL_fallback_retry(pthread_rwlock_rdlock, &lock->lock)) { + return; + } +#endif abort(); } } void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) { - if (pthread_rwlock_wrlock(&lock->lock) != 0) { + const int result = pthread_rwlock_wrlock(&lock->lock); + if (result != 0) { +#ifdef __MINGW32__ + if (result == EINVAL && + 0 == rwlock_EINVAL_fallback_retry(pthread_rwlock_wrlock, &lock->lock)) { + return; + } +#endif abort(); } }