]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
convert rand_meth_lock to atomics
authorNeil Horman <nhorman@openssl.org>
Wed, 1 Apr 2026 18:37:52 +0000 (14:37 -0400)
committerNikola Pajkovsky <nikolap@openssl.org>
Tue, 14 Apr 2026 08:29:28 +0000 (10:29 +0200)
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)

crypto/rand/rand_lib.c

index 227763e601a50180f15405bd4117533c6a8f2d14..a99bc7b6c630d04d67b744d4339513081f2afaa2 100644 (file)
@@ -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 */