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);