]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - crypto/conf/conf_mod.c
Add exemplar use case for rcu locks
[thirdparty/openssl.git] / crypto / conf / conf_mod.c
index d6a5f3ff3556bfaf6b1344a16064095c5b5d8070..e10c18a29faaecd2819da21a75c28dcd5c5f437d 100644 (file)
@@ -11,6 +11,7 @@
 #define OPENSSL_SUPPRESS_DEPRECATED
 
 #include "internal/cryptlib.h"
+#include "internal/rcu.h"
 #include <stdio.h>
 #include <ctype.h>
 #include <openssl/crypto.h>
@@ -63,7 +64,7 @@ struct conf_imodule_st {
 };
 
 static CRYPTO_ONCE init_module_list_lock = CRYPTO_ONCE_STATIC_INIT;
-static CRYPTO_RWLOCK *module_list_lock = NULL;
+static CRYPTO_RCU_LOCK *module_list_lock = NULL;
 static STACK_OF(CONF_MODULE) *supported_modules = NULL; /* protected by lock */
 static STACK_OF(CONF_IMODULE) *initialized_modules = NULL; /* protected by lock */
 
@@ -86,7 +87,7 @@ static int conf_modules_finish_int(void);
 
 static void module_lists_free(void)
 {
-    CRYPTO_THREAD_lock_free(module_list_lock);
+    ossl_rcu_lock_free(module_list_lock);
     module_list_lock = NULL;
 
     sk_CONF_MODULE_free(supported_modules);
@@ -98,7 +99,7 @@ static void module_lists_free(void)
 
 DEFINE_RUN_ONCE_STATIC(do_init_module_list_lock)
 {
-    module_list_lock = CRYPTO_THREAD_lock_new();
+    module_list_lock = ossl_rcu_lock_new(1);
     if (module_list_lock == NULL) {
         ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB);
         return 0;
@@ -327,17 +328,24 @@ static CONF_MODULE *module_add(DSO *dso, const char *name,
                                conf_init_func *ifunc, conf_finish_func *ffunc)
 {
     CONF_MODULE *tmod = NULL;
+    STACK_OF(CONF_MODULE) *old_modules;
+    STACK_OF(CONF_MODULE) *new_modules;
 
     if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
         return NULL;
 
-    if (!CRYPTO_THREAD_write_lock(module_list_lock))
-        return NULL;
+    ossl_rcu_write_lock(module_list_lock);
+
+    old_modules = ossl_rcu_deref(&supported_modules);
+
+    if (old_modules == NULL)
+        new_modules = sk_CONF_MODULE_new_null();
+    else
+        new_modules = sk_CONF_MODULE_dup(old_modules);
 
-    if (supported_modules == NULL)
-        supported_modules = sk_CONF_MODULE_new_null();
-    if (supported_modules == NULL)
+    if (new_modules == NULL)
         goto err;
+
     if ((tmod = OPENSSL_zalloc(sizeof(*tmod))) == NULL)
         goto err;
 
@@ -348,14 +356,18 @@ static CONF_MODULE *module_add(DSO *dso, const char *name,
     if (tmod->name == NULL)
         goto err;
 
-    if (!sk_CONF_MODULE_push(supported_modules, tmod))
+    if (!sk_CONF_MODULE_push(new_modules, tmod))
         goto err;
 
-    CRYPTO_THREAD_unlock(module_list_lock);
+    ossl_rcu_assign_ptr(&supported_modules, &new_modules);
+    ossl_rcu_write_unlock(module_list_lock);
+    ossl_synchronize_rcu(module_list_lock);
+
+    sk_CONF_MODULE_free(old_modules);
     return tmod;
 
  err:
-    CRYPTO_THREAD_unlock(module_list_lock);
+    ossl_rcu_write_unlock(module_list_lock);
     if (tmod != NULL) {
         OPENSSL_free(tmod->name);
         OPENSSL_free(tmod);
@@ -374,6 +386,8 @@ static CONF_MODULE *module_find(const char *name)
     CONF_MODULE *tmod;
     int i, nchar;
     char *p;
+    STACK_OF(CONF_MODULE) *mods;
+
     p = strrchr(name, '.');
 
     if (p)
@@ -384,18 +398,18 @@ static CONF_MODULE *module_find(const char *name)
     if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
         return NULL;
 
-    if (!CRYPTO_THREAD_read_lock(module_list_lock))
-        return NULL;
+    ossl_rcu_read_lock(module_list_lock);
+    mods = ossl_rcu_deref(&supported_modules);
 
-    for (i = 0; i < sk_CONF_MODULE_num(supported_modules); i++) {
-        tmod = sk_CONF_MODULE_value(supported_modules, i);
+    for (i = 0; i < sk_CONF_MODULE_num(mods); i++) {
+        tmod = sk_CONF_MODULE_value(mods, i);
         if (strncmp(tmod->name, name, nchar) == 0) {
-            CRYPTO_THREAD_unlock(module_list_lock);
+            ossl_rcu_read_unlock(module_list_lock);
             return tmod;
         }
     }
 
-    CRYPTO_THREAD_unlock(module_list_lock);
+    ossl_rcu_read_unlock(module_list_lock);
     return NULL;
 }
 
@@ -406,6 +420,8 @@ static int module_init(CONF_MODULE *pmod, const char *name, const char *value,
     int ret = 1;
     int init_called = 0;
     CONF_IMODULE *imod = NULL;
+    STACK_OF(CONF_IMODULE) *old_modules;
+    STACK_OF(CONF_IMODULE) *new_modules;
 
     /* Otherwise add initialized module to list */
     imod = OPENSSL_malloc(sizeof(*imod));
@@ -432,27 +448,33 @@ static int module_init(CONF_MODULE *pmod, const char *name, const char *value,
     if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
         goto err;
 
-    if (!CRYPTO_THREAD_write_lock(module_list_lock))
-        goto err;
+    ossl_rcu_write_lock(module_list_lock);
 
-    if (initialized_modules == NULL) {
-        initialized_modules = sk_CONF_IMODULE_new_null();
-        if (initialized_modules == NULL) {
-            CRYPTO_THREAD_unlock(module_list_lock);
-            ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB);
-            goto err;
-        }
+    old_modules = ossl_rcu_deref(&initialized_modules);
+
+    if (old_modules == NULL)
+        new_modules = sk_CONF_IMODULE_new_null();
+    else
+        new_modules = sk_CONF_IMODULE_dup(old_modules);
+
+    if (new_modules == NULL) {
+        ossl_rcu_write_unlock(module_list_lock);
+        ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB);
+        goto err;
     }
 
-    if (!sk_CONF_IMODULE_push(initialized_modules, imod)) {
-        CRYPTO_THREAD_unlock(module_list_lock);
+    if (!sk_CONF_IMODULE_push(new_modules, imod)) {
+        ossl_rcu_write_unlock(module_list_lock);
         ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB);
         goto err;
     }
 
     pmod->links++;
 
-    CRYPTO_THREAD_unlock(module_list_lock);
+    ossl_rcu_assign_ptr(&initialized_modules, &new_modules);
+    ossl_rcu_write_unlock(module_list_lock);
+    ossl_synchronize_rcu(module_list_lock);
+    sk_CONF_IMODULE_free(old_modules);
     return ret;
 
  err:
@@ -482,30 +504,46 @@ void CONF_modules_unload(int all)
 {
     int i;
     CONF_MODULE *md;
+    STACK_OF(CONF_MODULE) *old_modules;
+    STACK_OF(CONF_MODULE) *new_modules;
+    STACK_OF(CONF_MODULE) *to_delete;
 
     if (!conf_modules_finish_int()) /* also inits module list lock */
         return;
 
-    if (!CRYPTO_THREAD_write_lock(module_list_lock))
+    ossl_rcu_write_lock(module_list_lock);
+
+    old_modules = ossl_rcu_deref(&supported_modules);
+    new_modules = sk_CONF_MODULE_dup(old_modules);
+    to_delete = sk_CONF_MODULE_new_null();
+
+    if (new_modules == NULL) {
+        ossl_rcu_write_unlock(module_list_lock);
         return;
+    }
 
     /* unload modules in reverse order */
-    for (i = sk_CONF_MODULE_num(supported_modules) - 1; i >= 0; i--) {
-        md = sk_CONF_MODULE_value(supported_modules, i);
+    for (i = sk_CONF_MODULE_num(new_modules) - 1; i >= 0; i--) {
+        md = sk_CONF_MODULE_value(new_modules, i);
         /* If static or in use and 'all' not set ignore it */
         if (((md->links > 0) || !md->dso) && !all)
             continue;
         /* Since we're working in reverse this is OK */
-        (void)sk_CONF_MODULE_delete(supported_modules, i);
-        module_free(md);
+        (void)sk_CONF_MODULE_delete(new_modules, i);
+        sk_CONF_MODULE_push(to_delete, md);
     }
 
-    if (sk_CONF_MODULE_num(supported_modules) == 0) {
-        sk_CONF_MODULE_free(supported_modules);
-        supported_modules = NULL;
+    if (sk_CONF_MODULE_num(new_modules) == 0) {
+        sk_CONF_MODULE_free(new_modules);
+        new_modules = NULL;
     }
 
-    CRYPTO_THREAD_unlock(module_list_lock);
+    ossl_rcu_assign_ptr(&supported_modules, &new_modules);
+    ossl_rcu_write_unlock(module_list_lock);
+    ossl_synchronize_rcu(module_list_lock);
+    sk_CONF_MODULE_free(old_modules);
+    sk_CONF_MODULE_pop_free(to_delete, module_free);
+
 }
 
 /* unload a single module */
@@ -521,23 +559,27 @@ static void module_free(CONF_MODULE *md)
 static int conf_modules_finish_int(void)
 {
     CONF_IMODULE *imod;
+    STACK_OF(CONF_IMODULE) *old_modules;
+    STACK_OF(CONF_IMODULE) *new_modules = NULL;
 
     if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
         return 0;
 
     /* If module_list_lock is NULL here it means we were already unloaded */
-    if (module_list_lock == NULL
-        || !CRYPTO_THREAD_write_lock(module_list_lock))
+    if (module_list_lock == NULL)
         return 0;
 
-    while (sk_CONF_IMODULE_num(initialized_modules) > 0) {
-        imod = sk_CONF_IMODULE_pop(initialized_modules);
+    ossl_rcu_write_lock(module_list_lock);
+    old_modules = ossl_rcu_deref(&initialized_modules);
+    ossl_rcu_assign_ptr(&initialized_modules, &new_modules);
+    ossl_rcu_write_unlock(module_list_lock);
+    ossl_synchronize_rcu(module_list_lock);
+
+    while (sk_CONF_IMODULE_num(old_modules) > 0) {
+        imod = sk_CONF_IMODULE_pop(old_modules);
         module_finish(imod);
     }
-    sk_CONF_IMODULE_free(initialized_modules);
-    initialized_modules = NULL;
-
-    CRYPTO_THREAD_unlock(module_list_lock);
+    sk_CONF_IMODULE_free(old_modules);
 
     return 1;
 }