Commit 01fba667c2 for openssl.org

commit 01fba667c2ff256ae83d814cbb7fa882a04353b8
Author: Bob Beck <beck@openssl.org>
Date:   Wed Apr 8 13:11:06 2026 -0600

    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 <paul.dale@oracle.com>
    Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
    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 9472cb437a..c3314217bd 100644
--- a/crypto/threads_pthread.c
+++ b/crypto/threads_pthread.c
@@ -62,18 +62,6 @@
 #include <atomic.h>
 #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 33b373f25d..29be4179bd 100644
--- a/crypto/threads_win.c
+++ b/crypto/threads_win.c
@@ -15,18 +15,6 @@
 #endif
 #include <assert.h>

-/*
- * 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 <openssl/crypto.h>
 #include <crypto/cryptlib.h>
 #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 5452942574..fd114c3dd8 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