ex_data: convert to new-style locking.
Change-Id: Id81f986f433805837b58a6ddd13ec146ff62c30b
Reviewed-on: https://boringssl-review.googlesource.com/4323
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/ex_data.c b/crypto/ex_data.c
index d399b83..7002eec 100644
--- a/crypto/ex_data.c
+++ b/crypto/ex_data.c
@@ -122,37 +122,32 @@
/* global_impl is the implementation that we use at runtime. */
static const CRYPTO_EX_DATA_IMPL *global_impl = NULL;
+/* global_impl_once protects the call to |global_impl_init|. */
+static CRYPTO_once_t global_impl_once = CRYPTO_ONCE_INIT;
+
+/* global_user_set_impl is a pointer to a user provided implementation. If this
+ * is non-NULL at the point of the first use of ex_data, |global_impl| will be
+ * set to this value. */
+static const CRYPTO_EX_DATA_IMPL *global_user_set_impl = NULL;
+
/* ex_data_default_impl is a the default implementation, defined in
* ex_data_impl.c. */
extern const CRYPTO_EX_DATA_IMPL ex_data_default_impl;
-/* get_impl returns the current ex_data implementatation. */
-static const CRYPTO_EX_DATA_IMPL *get_impl(void) {
- const CRYPTO_EX_DATA_IMPL *impl;
-
- CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
- impl = global_impl;
- CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
-
- if (impl != NULL) {
- return impl;
- }
-
- CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
+/* global_impl_init is called once in order to set |global_impl|. */
+static void global_impl_init(void) {
+ global_impl = global_user_set_impl;
if (global_impl == NULL) {
global_impl = &ex_data_default_impl;
}
- impl = global_impl;
- CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
- return impl;
}
int CRYPTO_get_ex_new_index(int class_value, long argl, void *argp,
CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
CRYPTO_EX_free *free_func) {
- const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
- return impl->get_new_index(class_value, argl, argp, new_func, dup_func,
- free_func);
+ CRYPTO_once(&global_impl_once, global_impl_init);
+ return global_impl->get_new_index(class_value, argl, argp, new_func, dup_func,
+ free_func);
}
int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int index, void *val) {
@@ -188,44 +183,38 @@
}
int CRYPTO_ex_data_new_class(void) {
- const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
- return impl->new_class();
+ CRYPTO_once(&global_impl_once, global_impl_init);
+ return global_impl->new_class();
}
int CRYPTO_new_ex_data(int class_value, void *obj, CRYPTO_EX_DATA *ad) {
- const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
- return impl->new_ex_data(class_value, obj, ad);
+ CRYPTO_once(&global_impl_once, global_impl_init);
+ return global_impl->new_ex_data(class_value, obj, ad);
}
int CRYPTO_dup_ex_data(int class_value, CRYPTO_EX_DATA *to,
const CRYPTO_EX_DATA *from) {
- const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
- return impl->dup_ex_data(class_value, to, from);
+ CRYPTO_once(&global_impl_once, global_impl_init);
+ return global_impl->dup_ex_data(class_value, to, from);
}
void CRYPTO_free_ex_data(int class_value, void *obj, CRYPTO_EX_DATA *ad) {
- const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
- impl->free_ex_data(class_value, obj, ad);
+ CRYPTO_once(&global_impl_once, global_impl_init);
+ global_impl->free_ex_data(class_value, obj, ad);
}
const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void) {
- return get_impl();
+ CRYPTO_once(&global_impl_once, global_impl_init);
+ return global_impl;
}
int CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *impl) {
- int ret = 0;
-
- CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
- if (global_impl == NULL) {
- ret = 1;
- global_impl = impl;
- }
- CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
-
- return ret;
+ global_user_set_impl = impl;
+ CRYPTO_once(&global_impl_once, global_impl_init);
+ return (global_impl == impl);
}
void CRYPTO_cleanup_all_ex_data(void) {
- const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
- impl->cleanup();
+ CRYPTO_once(&global_impl_once, global_impl_init);
+ global_impl->cleanup();
}
diff --git a/crypto/ex_data_impl.c b/crypto/ex_data_impl.c
index f55b369..09295df 100644
--- a/crypto/ex_data_impl.c
+++ b/crypto/ex_data_impl.c
@@ -132,15 +132,19 @@
int class_value;
} EX_CLASS_ITEM;
+static CRYPTO_once_t global_classes_once = CRYPTO_ONCE_INIT;
+static struct CRYPTO_STATIC_MUTEX global_classes_lock =
+ CRYPTO_STATIC_MUTEX_INIT;
static LHASH_OF(EX_CLASS_ITEM) *global_classes = NULL;
+static struct CRYPTO_STATIC_MUTEX global_next_class_lock =
+ CRYPTO_STATIC_MUTEX_INIT;
static int global_next_class = 100;
static int new_class(void) {
- int ret;
- CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
- ret = global_next_class++;
- CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+ CRYPTO_STATIC_MUTEX_lock_write(&global_next_class_lock);
+ const int ret = global_next_class++;
+ CRYPTO_STATIC_MUTEX_unlock(&global_next_class_lock);
return ret;
}
@@ -170,50 +174,34 @@
OPENSSL_free(item);
}
-static LHASH_OF(EX_CLASS_ITEM) *get_classes(void) {
- LHASH_OF(EX_CLASS_ITEM) *ret;
-
- CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
- ret = global_classes;
- CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
-
- if (ret != NULL) {
- return ret;
- }
-
- CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
- if (global_classes == NULL) {
- global_classes = lh_EX_CLASS_ITEM_new(class_hash, class_cmp);
- }
- ret = global_classes;
- CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
-
- return ret;
+static void global_classes_init(void) {
+ global_classes = lh_EX_CLASS_ITEM_new(class_hash, class_cmp);
}
static void cleanup(void) {
- LHASH_OF(EX_CLASS_ITEM) *classes = get_classes();
+ CRYPTO_once(&global_classes_once, global_classes_init);
- if (classes != NULL) {
- lh_EX_CLASS_ITEM_doall(classes, class_free);
- lh_EX_CLASS_ITEM_free(classes);
+ if (global_classes != NULL) {
+ lh_EX_CLASS_ITEM_doall(global_classes, class_free);
+ lh_EX_CLASS_ITEM_free(global_classes);
}
global_classes = NULL;
}
static EX_CLASS_ITEM *get_class(int class_value) {
- LHASH_OF(EX_CLASS_ITEM) *const classes = get_classes();
EX_CLASS_ITEM template, *class_item;
int ok = 0;
- if (classes == NULL) {
+ CRYPTO_once(&global_classes_once, global_classes_init);
+
+ if (global_classes == NULL) {
return NULL;
}
- CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
+ CRYPTO_STATIC_MUTEX_lock_write(&global_classes_lock);
template.class_value = class_value;
- class_item = lh_EX_CLASS_ITEM_retrieve(classes, &template);
+ class_item = lh_EX_CLASS_ITEM_retrieve(global_classes, &template);
if (class_item != NULL) {
ok = 1;
} else {
@@ -223,12 +211,12 @@
class_item->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null();
if (class_item->meth != NULL) {
EX_CLASS_ITEM *old_data;
- ok = lh_EX_CLASS_ITEM_insert(classes, &old_data, class_item);
+ ok = lh_EX_CLASS_ITEM_insert(global_classes, &old_data, class_item);
assert(old_data == NULL);
}
}
}
- CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+ CRYPTO_STATIC_MUTEX_unlock(&global_classes_lock);
if (!ok) {
if (class_item) {
@@ -268,7 +256,7 @@
funcs->dup_func = dup_func;
funcs->free_func = free_func;
- CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
+ CRYPTO_STATIC_MUTEX_lock_write(&global_classes_lock);
if (!sk_CRYPTO_EX_DATA_FUNCS_push(item->meth, funcs)) {
OPENSSL_PUT_ERROR(CRYPTO, get_new_index, ERR_R_MALLOC_FAILURE);
@@ -279,7 +267,7 @@
ret = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth) - 1;
err:
- CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+ CRYPTO_STATIC_MUTEX_unlock(&global_classes_lock);
return ret;
}
@@ -301,12 +289,12 @@
/* CRYPTO_EX_DATA_FUNCS structures are static once set, so we can take a
* shallow copy of the list under lock and then use the structures without
* the lock held. */
- CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
+ CRYPTO_STATIC_MUTEX_lock_read(&global_classes_lock);
n = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth);
if (n > 0) {
*out = sk_CRYPTO_EX_DATA_FUNCS_dup(item->meth);
}
- CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
+ CRYPTO_STATIC_MUTEX_unlock(&global_classes_lock);
if (n > 0 && *out == NULL) {
OPENSSL_PUT_ERROR(CRYPTO, get_func_pointers, ERR_R_MALLOC_FAILURE);