Commit 91072b2039 for openssl.org
commit 91072b2039e844d089ad3f6e8cc1689f366ac92c
Author: Neil Horman <nhorman@openssl.org>
Date: Wed Apr 1 14:37:52 2026 -0400
convert rand_meth_lock to atomics
Using our previously created atomic ops, we can (almost) eliminate the
use of the rand_meth_lock. This lock guards reads/write on the
RAND_default_meth global variable, which is generally written only once
during a process lifetime. By replacing the lock with an atomic read
for reads, and an atomic compare and exchange or atomic store for
writes, we can significantly improve the execution time of
RAND_get_rand_method, which is called every time a process calls
RAND_bytes_ex()
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
MergeDate: Tue Apr 14 08:29:31 2026
(Merged from https://github.com/openssl/openssl/pull/30670)
diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c
index 227763e601..a99bc7b6c6 100644
--- a/crypto/rand/rand_lib.c
+++ b/crypto/rand/rand_lib.c
@@ -232,11 +232,9 @@ static int rand_set_rand_method_internal(const RAND_METHOD *meth,
return 0;
if (!RUN_ONCE(&rand_init, do_rand_init))
return 0;
-
- if (!CRYPTO_THREAD_write_lock(rand_meth_lock))
+ if (!CRYPTO_atomic_store_ptr((void **)&default_RAND_meth, (void **)&meth,
+ rand_meth_lock))
return 0;
- default_RAND_meth = meth;
- CRYPTO_THREAD_unlock(rand_meth_lock);
return 1;
}
@@ -250,24 +248,28 @@ const RAND_METHOD *RAND_get_rand_method(void)
const RAND_METHOD *tmp_meth = NULL;
if (!RUN_ONCE(&rand_init, do_rand_init))
- return NULL;
-
- if (rand_meth_lock == NULL)
- return NULL;
+ goto end;
- if (!CRYPTO_THREAD_read_lock(rand_meth_lock))
+ if (CRYPTO_atomic_load_ptr((void **)&default_RAND_meth, (void **)&tmp_meth,
+ rand_meth_lock)) {
+ if (tmp_meth != NULL)
+ return tmp_meth;
+ } else {
return NULL;
- tmp_meth = default_RAND_meth;
- CRYPTO_THREAD_unlock(rand_meth_lock);
- if (tmp_meth != NULL)
- return tmp_meth;
+ }
- if (!CRYPTO_THREAD_write_lock(rand_meth_lock))
- return NULL;
- if (default_RAND_meth == NULL)
- default_RAND_meth = &ossl_rand_meth;
- tmp_meth = default_RAND_meth;
- CRYPTO_THREAD_unlock(rand_meth_lock);
+ /*
+ * We atomically compare and exchange default_RAND_meth
+ * if default_RAND_meth is NULL, we assign ossl_rand_meth to it
+ * If this returns 1, then the exchange was successful, and we can just
+ * return &ossl_rand_meth
+ * If it fails, then the contents of default_RAND_meth are written to tmp_meth
+ * which we can just return as is
+ */
+ if (CRYPTO_atomic_cmp_exch_ptr((void **)&default_RAND_meth, (void **)&tmp_meth,
+ (void *)&ossl_rand_meth, rand_meth_lock))
+ tmp_meth = &ossl_rand_meth;
+end:
return tmp_meth;
}
#endif /* OPENSSL_NO_DEPRECATED_3_0 */