Add some more CRYPTO_atomic functions
authorMatt Caswell <matt@openssl.org>
Tue, 22 Dec 2020 17:43:07 +0000 (17:43 +0000)
committerDmitry Belyavskiy <beldmit@gmail.com>
Thu, 31 Dec 2020 12:14:38 +0000 (13:14 +0100)
We add an implementation for CRYPTO_atomic_or() and CRYPTO_atomic_load()

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/13733)

crypto/threads_none.c
crypto/threads_pthread.c
crypto/threads_win.c
include/openssl/crypto.h.in
util/libcrypto.num

index c12d5610aae1e6bcb69037727a5bd3e96102a9d6..55d4b5f0f867e202ec4ff8cd2423098c02339ced 100644 (file)
@@ -133,6 +133,22 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
     return 1;
 }
 
+int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
+                     CRYPTO_RWLOCK *lock)
+{
+    *val |= op;
+    *ret  = *val;
+
+    return 1;
+}
+
+int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
+{
+    *ret  = *val;
+
+    return 1;
+}
+
 int openssl_init_fork_handlers(void)
 {
     return 0;
index afc29b796145023c033672453d2848e60a57aff6..22ba79316126c31f66ef547ab491d621cc7f486f 100644 (file)
@@ -185,7 +185,7 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
         return 1;
     }
 # endif
-    if (!CRYPTO_THREAD_write_lock(lock))
+    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
         return 0;
 
     *val += amount;
@@ -197,6 +197,54 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
     return 1;
 }
 
+int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
+                     CRYPTO_RWLOCK *lock)
+{
+# if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL)
+    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))
+    /* This will work for all future Solaris versions. */
+    if (ret != NULL) {
+        *ret = atomic_or_64_nv(val, op);
+        return 1;
+    }
+# endif
+    if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
+        return 0;
+    *val |= op;
+    *ret  = *val;
+
+    if (!CRYPTO_THREAD_unlock(lock))
+        return 0;
+
+    return 1;
+}
+
+int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
+{
+# if defined(__GNUC__) && defined(__ATOMIC_ACQUIRE)
+    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))
+    /* This will work for all future Solaris versions. */
+    if (ret != NULL) {
+        *ret = atomic_or_64_nv(val, 0);
+        return 1;
+    }
+# endif
+    if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
+        return 0;
+    *ret  = *val;
+    if (!CRYPTO_THREAD_unlock(lock))
+        return 0;
+
+    return 1;
+}
 # ifndef FIPS_MODULE
 #  ifdef OPENSSL_SYS_UNIX
 
index a008831a3e77dedd29a97ffe5b6aeed18d4e0db5..ef68fe2d24a3b5eaa40727a284db76da76528fe0 100644 (file)
@@ -66,9 +66,9 @@ void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
     return;
 }
 
-#  define ONCE_UNINITED     0
-#  define ONCE_ININIT       1
-#  define ONCE_DONE         2
+# define ONCE_UNINITED     0
+# define ONCE_ININIT       1
+# define ONCE_DONE         2
 
 /*
  * We don't use InitOnceExecuteOnce because that isn't available in WinXP which
@@ -159,6 +159,19 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
     return 1;
 }
 
+int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
+                     CRYPTO_RWLOCK *lock)
+{
+    *ret = (uint64_t)InterlockedOr64((LONG64 volatile *)val, (LONG64)op) | op;
+    return 1;
+}
+
+int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
+{
+    *ret = (uint64_t)InterlockedOr64((LONG64 volatile *)val, 0);
+    return 1;
+}
+
 int openssl_init_fork_handlers(void)
 {
     return 0;
index 0641db3a44dfa9b5740d1b85a200237277e43fc4..0b9aeefe0480826c30d0ed5c9b1d1b708e2a17b5 100644 (file)
@@ -86,6 +86,9 @@ int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock);
 void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock);
 
 int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock);
+int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
+                     CRYPTO_RWLOCK *lock);
+int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock);
 
 /* No longer needed, so this is a no-op */
 #define OPENSSL_malloc_init() while(0) continue
index 93ca779831bcd05bc878ac6355779811bc49e7c6..289a6672f93b31b51952b628eacf2a42543278f0 100644 (file)
@@ -5284,3 +5284,5 @@ PEM_write_bio_PrivateKey_ex             ? 3_0_0   EXIST::FUNCTION:
 PEM_write_PUBKEY_ex                     ?      3_0_0   EXIST::FUNCTION:STDIO
 PEM_write_bio_PUBKEY_ex                 ?      3_0_0   EXIST::FUNCTION:
 EVP_PKEY_get_group_name                 ?      3_0_0   EXIST::FUNCTION:
+CRYPTO_atomic_or                        ?      3_0_0   EXIST::FUNCTION:
+CRYPTO_atomic_load                      ?      3_0_0   EXIST::FUNCTION: