From: Bob Beck Date: Wed, 8 Apr 2026 19:11:06 +0000 (-0600) Subject: Add an OSSL_ATOMICS_LOCKLESS internal define X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=01fba667c2ff256ae83d814cbb7fa882a04353b8;p=thirdparty%2Fopenssl.git Add an OSSL_ATOMICS_LOCKLESS internal define So that we can decide to decide to do fast path things with conditional compilaiton, and avoid adding a lock to save a lock Reviewed-by: Paul Dale Reviewed-by: Nikola Pajkovsky MergeDate: Thu Apr 30 11:52:47 2026 (Merged from https://github.com/openssl/openssl/pull/30738) --- diff --git a/crypto/threads_pthread.c b/crypto/threads_pthread.c index 9472cb437aa..c3314217bda 100644 --- a/crypto/threads_pthread.c +++ b/crypto/threads_pthread.c @@ -62,18 +62,6 @@ #include #endif -#if defined(__apple_build_version__) && __apple_build_version__ < 6000000 -/* - * OS/X 10.7 and 10.8 had a weird version of clang which has __ATOMIC_ACQUIRE and - * __ATOMIC_ACQ_REL but which expects only one parameter for __atomic_is_lock_free() - * rather than two which has signature __atomic_is_lock_free(sizeof(_Atomic(T))). - * All of this makes impossible to use __atomic_is_lock_free here. - * - * See: https://github.com/llvm/llvm-project/commit/a4c2602b714e6c6edb98164550a5ae829b2de760 - */ -#define BROKEN_CLANG_ATOMICS -#endif - #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && !defined(OPENSSL_SYS_WINDOWS) #if defined(OPENSSL_SYS_UNIX) @@ -117,8 +105,7 @@ */ typedef void *pvoid; -#if defined(__GNUC__) && defined(__ATOMIC_ACQUIRE) && !defined(BROKEN_CLANG_ATOMICS) \ - && !defined(USE_ATOMIC_FALLBACKS) +#if defined(USE_GCC_ATOMICS) #define ATOMIC_LOAD_N(t, p, o) __atomic_load_n(p, o) #define ATOMIC_STORE_N(t, p, v, o) __atomic_store_n(p, v, o) #define ATOMIC_STORE(t, p, v, o) __atomic_store(p, v, o) @@ -1058,12 +1045,12 @@ int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b) int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock) { -#if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS) +#if defined(USE_GCC_ATOMICS) if (__atomic_is_lock_free(sizeof(*val), val)) { *ret = __atomic_add_fetch(val, amount, __ATOMIC_ACQ_REL); return 1; } -#elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11)) +#elif defined(USE_SOLARIS_ATOMICS) /* This will work for all future Solaris versions. */ if (ret != NULL) { *ret = atomic_add_int_nv((volatile unsigned int *)val, amount); @@ -1085,12 +1072,12 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock) int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock) { -#if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS) +#if defined(USE_GCC_ATOMICS) if (__atomic_is_lock_free(sizeof(*val), val)) { *ret = __atomic_add_fetch(val, op, __ATOMIC_ACQ_REL); return 1; } -#elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11)) +#elif defined(USE_SOLARIS_ATOMICS) /* This will work for all future Solaris versions. */ if (ret != NULL) { *ret = atomic_add_64_nv(val, op); @@ -1111,12 +1098,12 @@ int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret, int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock) { -#if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS) +#if defined(USE_GCC_ATOMICS) if (__atomic_is_lock_free(sizeof(*val), val)) { *ret = __atomic_and_fetch(val, op, __ATOMIC_ACQ_REL); return 1; } -#elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11)) +#elif defined(USE_SOLARIS_ATOMICS) /* This will work for all future Solaris versions. */ if (ret != NULL) { *ret = atomic_and_64_nv(val, op); @@ -1137,12 +1124,12 @@ int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret, int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock) { -#if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS) +#if defined(USE_GCC_ATOMICS) if (__atomic_is_lock_free(sizeof(*val), val)) { *ret = __atomic_or_fetch(val, op, __ATOMIC_ACQ_REL); return 1; } -#elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11)) +#elif defined(USE_SOLARIS_ATOMICS) /* This will work for all future Solaris versions. */ if (ret != NULL) { *ret = atomic_or_64_nv(val, op); @@ -1162,12 +1149,12 @@ int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret, int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock) { -#if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS) +#if defined(USE_GCC_ATOMICS) if (__atomic_is_lock_free(sizeof(*val), val)) { __atomic_load(val, ret, __ATOMIC_ACQUIRE); return 1; } -#elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11)) +#elif defined(USE_SOLARIS_ATOMICS) /* This will work for all future Solaris versions. */ if (ret != NULL) { *ret = atomic_or_64_nv(val, 0); @@ -1185,12 +1172,12 @@ int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock) int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock) { -#if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS) +#if defined(USE_GCC_ATOMICS) if (__atomic_is_lock_free(sizeof(*dst), dst)) { __atomic_store(dst, &val, __ATOMIC_RELEASE); return 1; } -#elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11)) +#elif defined(USE_SOLARIS_ATOMICS) /* This will work for all future Solaris versions. */ if (dst != NULL) { atomic_swap_64(dst, val); @@ -1208,12 +1195,12 @@ int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock) int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock) { -#if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS) +#if defined(USE_GCC_ATOMICS) if (__atomic_is_lock_free(sizeof(*val), val)) { __atomic_load(val, ret, __ATOMIC_ACQUIRE); return 1; } -#elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11)) +#elif defined(USE_SOLARIS_ATOMICS) /* This will work for all future Solaris versions. */ if (ret != NULL) { *ret = (int)atomic_or_uint_nv((unsigned int *)val, 0); @@ -1231,12 +1218,12 @@ int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock) int CRYPTO_atomic_store_int(int *dst, int val, CRYPTO_RWLOCK *lock) { -#if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS) +#if defined(USE_GCC_ATOMICS) if (__atomic_is_lock_free(sizeof(*dst), dst)) { __atomic_store(dst, &val, __ATOMIC_RELEASE); return 1; } -#elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11)) +#elif defined(USE_SOLARIS_ATOMICS) /* This will work for all future Solaris versions. */ if (dst != NULL) { atomic_swap_uint((unsigned int)dst, (unsigned int)val); diff --git a/crypto/threads_win.c b/crypto/threads_win.c index 33b373f25dd..29be4179bd2 100644 --- a/crypto/threads_win.c +++ b/crypto/threads_win.c @@ -15,18 +15,6 @@ #endif #include -/* - * VC++ 2008 or earlier x86 compilers do not have an inline implementation - * of InterlockedOr64 for 32bit and will fail to run on Windows XP 32bit. - * https://docs.microsoft.com/en-us/cpp/intrinsics/interlockedor-intrinsic-functions#requirements - * To work around this problem, we implement a manual locking mechanism for - * only VC++ 2008 or earlier x86 compilers. - */ - -#if ((defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER <= 1600) || (defined(__MINGW32__) && !defined(__MINGW64__))) -#define NO_INTERLOCKEDOR64 -#endif - #include #include #include "internal/common.h" @@ -120,7 +108,7 @@ struct rcu_lock_st { /* signal to wake threads waiting on prior_lock */ CRYPTO_CONDVAR *prior_signal; - /* lock used with NO_INTERLOCKEDOR64: VS2010 x86 */ + /* lock used without USE_INTERLOCKEDOR64: VS2010 x86, mingw32 */ CRYPTO_RWLOCK *rw_lock; }; @@ -339,7 +327,7 @@ static struct rcu_qp *update_qp(CRYPTO_RCU_LOCK *lock, uint32_t *curr_id) /* update the reader index to be the prior qp */ tmp = lock->current_alloc_idx; -#if (defined(NO_INTERLOCKEDOR64)) +#if (!defined(USE_INTERLOCKEDOR64)) /* This cannot fail, avoid unused result warning */ ossl_unused int r = CRYPTO_THREAD_write_lock(lock->rw_lock); lock->reader_idx = tmp; @@ -610,7 +598,7 @@ int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b) int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock) { -#if (defined(NO_INTERLOCKEDOR64)) +#if (!defined(USE_INTERLOCKEDOR64)) OPENSSL_assert(lock != NULL); if (!CRYPTO_THREAD_write_lock(lock)) return 0; @@ -631,7 +619,7 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock) int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock) { -#if (defined(NO_INTERLOCKEDOR64)) +#if (!defined(USE_INTERLOCKEDOR64)) OPENSSL_assert(lock != NULL); if (!CRYPTO_THREAD_write_lock(lock)) return 0; @@ -651,7 +639,7 @@ int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret, int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock) { -#if (defined(NO_INTERLOCKEDOR64)) +#if (!defined(USE_INTERLOCKEDOR64)) OPENSSL_assert(lock != NULL); if (!CRYPTO_THREAD_write_lock(lock)) return 0; @@ -671,7 +659,7 @@ int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret, int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock) { -#if (defined(NO_INTERLOCKEDOR64)) +#if (!defined(USE_INTERLOCKEDOR64)) OPENSSL_assert(lock != NULL); if (!CRYPTO_THREAD_write_lock(lock)) return 0; @@ -690,7 +678,7 @@ int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret, int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock) { -#if (defined(NO_INTERLOCKEDOR64)) +#if (!defined(USE_INTERLOCKEDOR64)) OPENSSL_assert(lock != NULL); if (!CRYPTO_THREAD_read_lock(lock)) return 0; @@ -707,7 +695,7 @@ int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock) int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock) { -#if (defined(NO_INTERLOCKEDOR64)) +#if (!defined(USE_INTERLOCKEDOR64)) OPENSSL_assert(lock != NULL); if (!CRYPTO_THREAD_read_lock(lock)) return 0; @@ -724,7 +712,7 @@ int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock) int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock) { -#if (defined(NO_INTERLOCKEDOR64)) +#if (!defined(USE_INTERLOCKEDOR64)) OPENSSL_assert(lock != NULL); if (!CRYPTO_THREAD_read_lock(lock)) return 0; @@ -742,7 +730,7 @@ int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock) int CRYPTO_atomic_store_int(int *dst, int val, CRYPTO_RWLOCK *lock) { -#if (defined(NO_INTERLOCKEDOR64)) +#if (!defined(USE_INTERLOCKEDOR64)) OPENSSL_assert(lock != NULL); if (!CRYPTO_THREAD_read_lock(lock)) return 0; diff --git a/include/internal/threads_common.h b/include/internal/threads_common.h index 54529425749..fd114c3dd82 100644 --- a/include/internal/threads_common.h +++ b/include/internal/threads_common.h @@ -48,4 +48,46 @@ int CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_KEY_ID id, void CRYPTO_THREAD_clean_local(void); +/* Do atomics work? */ + +#if defined(__apple_build_version__) && __apple_build_version__ < 6000000 +/* + * OS/X 10.7 and 10.8 had a weird version of clang which has __ATOMIC_ACQUIRE and + * __ATOMIC_ACQ_REL but which expects only one parameter for __atomic_is_lock_free() + * rather than two which has signature __atomic_is_lock_free(sizeof(_Atomic(T))). + * All of this makes impossible to use __atomic_is_lock_free here. + * + * See: https://github.com/llvm/llvm-project/commit/a4c2602b714e6c6edb98164550a5ae829b2de760 + */ +#define BROKEN_CLANG_ATOMICS +#endif + +/* + * VC++ 2008 or earlier x86 compilers do not have an inline implementation + * of InterlockedOr64 for 32bit and will fail to run on Windows XP 32bit. + * https://docs.microsoft.com/en-us/cpp/intrinsics/interlockedor-intrinsic-functions#requirements + * To work around this problem, we implement a manual locking mechanism for + * only VC++ 2008 or earlier x86 compilers. + */ + +#if defined(_MSC_VER) +#if (!defined(_M_IX86) || _MSC_VER > 1600) +#define USE_INTERLOCKEDOR64 +#endif +#elif defined(__MINGW64__) +#define USE_INTERLOCKEDOR64 +#endif + +#if defined(__GNUC__) && defined(__ATOMIC_ACQUIRE) && !defined(BROKEN_CLANG_ATOMICS) \ + && !defined(USE_ATOMIC_FALLBACKS) +#define OSSL_USE_GCC_ATOMICS +#elif defined(__sun) && (defined(__SunOS_5_10) || defined(__SunOS_5_11)) +#define OSSL_USE_SOLARIS_ATOMICS +#endif + +/* Allow us to know if atomics will be implemented with a fallback lock or not. */ +#if defined(OSSL_USE_GCC_ATOMICS) || defined(OSSL_USE_SOLARIS_ATOMICS) || defined(USE_INTERLOCKEDOR64) +#define OSSL_ATOMICS_LOCKLESS +#endif + #endif