diff --git a/crypto/conf/conf_mod.c b/crypto/conf/conf_mod.c index 7efb982054..5c1d00d27c 100644 --- a/crypto/conf/conf_mod.c +++ b/crypto/conf/conf_mod.c @@ -99,7 +99,7 @@ static void module_lists_free(void) DEFINE_RUN_ONCE_STATIC(do_init_module_list_lock) { - module_list_lock = ossl_rcu_lock_new(1); + module_list_lock = ossl_rcu_lock_new(1, NULL); if (module_list_lock == NULL) { ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB); return 0; diff --git a/crypto/context.c b/crypto/context.c index 33d52a964b..3d55084d7b 100644 --- a/crypto/context.c +++ b/crypto/context.c @@ -29,6 +29,7 @@ struct ossl_lib_ctx_st { void *global_properties; void *drbg; void *drbg_nonce; + CRYPTO_THREAD_LOCAL rcu_local_key; #ifndef FIPS_MODULE void *provider_conf; void *bio_core; @@ -81,9 +82,12 @@ static int context_init(OSSL_LIB_CTX *ctx) { int exdata_done = 0; + if (!CRYPTO_THREAD_init_local(&ctx->rcu_local_key, NULL)) + return 0; + ctx->lock = CRYPTO_THREAD_lock_new(); if (ctx->lock == NULL) - return 0; + goto err; ctx->rand_crngt_lock = CRYPTO_THREAD_lock_new(); if (ctx->rand_crngt_lock == NULL) @@ -209,6 +213,7 @@ static int context_init(OSSL_LIB_CTX *ctx) CRYPTO_THREAD_lock_free(ctx->rand_crngt_lock); CRYPTO_THREAD_lock_free(ctx->lock); + CRYPTO_THREAD_cleanup_local(&ctx->rcu_local_key); memset(ctx, '\0', sizeof(*ctx)); return 0; } @@ -355,6 +360,7 @@ static int context_deinit(OSSL_LIB_CTX *ctx) CRYPTO_THREAD_lock_free(ctx->lock); ctx->rand_crngt_lock = NULL; ctx->lock = NULL; + CRYPTO_THREAD_cleanup_local(&ctx->rcu_local_key); return 1; } @@ -652,3 +658,11 @@ const char *ossl_lib_ctx_get_descriptor(OSSL_LIB_CTX *libctx) return "Non-default library context"; #endif } + +CRYPTO_THREAD_LOCAL *ossl_lib_ctx_get_rcukey(OSSL_LIB_CTX *libctx) +{ + libctx = ossl_lib_ctx_get_concrete(libctx); + if (libctx == NULL) + return NULL; + return &libctx->rcu_local_key; +} diff --git a/crypto/threads_none.c b/crypto/threads_none.c index c57c59bde8..47a7c01f26 100644 --- a/crypto/threads_none.c +++ b/crypto/threads_none.c @@ -23,7 +23,7 @@ struct rcu_lock_st { struct rcu_cb_item *cb_items; }; -CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers) +CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx) { struct rcu_lock_st *lock; diff --git a/crypto/threads_pthread.c b/crypto/threads_pthread.c index 30540f5e8a..f7e350c0b4 100644 --- a/crypto/threads_pthread.c +++ b/crypto/threads_pthread.c @@ -244,8 +244,6 @@ static inline uint64_t fallback_atomic_or_fetch(uint64_t *p, uint64_t m) # define ATOMIC_OR_FETCH(p, v, o) fallback_atomic_or_fetch(p, v) # endif -static CRYPTO_THREAD_LOCAL rcu_thr_key; - /* * users is broken up into 2 parts * bits 0-15 current readers @@ -300,6 +298,9 @@ struct rcu_lock_st { /* Callbacks to call for next ossl_synchronize_rcu */ struct rcu_cb_item *cb_items; + /* The context we are being created against */ + OSSL_LIB_CTX *ctx; + /* rcu generation counter for in-order retirement */ uint32_t id_ctr; @@ -337,24 +338,6 @@ struct rcu_lock_st { pthread_cond_t prior_signal; }; -/* - * Called on thread exit to free the pthread key - * associated with this thread, if any - */ -static void free_rcu_thr_data(void *ptr) -{ - struct rcu_thr_data *data = - (struct rcu_thr_data *)CRYPTO_THREAD_get_local(&rcu_thr_key); - - OPENSSL_free(data); - CRYPTO_THREAD_set_local(&rcu_thr_key, NULL); -} - -static void ossl_rcu_init(void) -{ - CRYPTO_THREAD_init_local(&rcu_thr_key, NULL); -} - /* Read side acquisition of the current qp */ static struct rcu_qp *get_hold_current_qp(struct rcu_lock_st *lock) { @@ -403,22 +386,31 @@ static struct rcu_qp *get_hold_current_qp(struct rcu_lock_st *lock) return &lock->qp_group[qp_idx]; } +static void ossl_rcu_free_local_data(void *arg) +{ + OSSL_LIB_CTX *ctx = arg; + CRYPTO_THREAD_LOCAL *lkey = ossl_lib_ctx_get_rcukey(ctx); + struct rcu_thr_data *data = CRYPTO_THREAD_get_local(lkey); + OPENSSL_free(data); +} + void ossl_rcu_read_lock(CRYPTO_RCU_LOCK *lock) { struct rcu_thr_data *data; int i, available_qp = -1; + CRYPTO_THREAD_LOCAL *lkey = ossl_lib_ctx_get_rcukey(lock->ctx); /* * we're going to access current_qp here so ask the * processor to fetch it */ - data = CRYPTO_THREAD_get_local(&rcu_thr_key); + data = CRYPTO_THREAD_get_local(lkey); if (data == NULL) { data = OPENSSL_zalloc(sizeof(*data)); OPENSSL_assert(data != NULL); - CRYPTO_THREAD_set_local(&rcu_thr_key, data); - ossl_init_thread_start(NULL, NULL, free_rcu_thr_data); + CRYPTO_THREAD_set_local(lkey, data); + ossl_init_thread_start(NULL, lock->ctx, ossl_rcu_free_local_data); } for (i = 0; i < MAX_QPS; i++) { @@ -444,7 +436,8 @@ void ossl_rcu_read_lock(CRYPTO_RCU_LOCK *lock) void ossl_rcu_read_unlock(CRYPTO_RCU_LOCK *lock) { int i; - struct rcu_thr_data *data = CRYPTO_THREAD_get_local(&rcu_thr_key); + CRYPTO_THREAD_LOCAL *lkey = ossl_lib_ctx_get_rcukey(lock->ctx); + struct rcu_thr_data *data = CRYPTO_THREAD_get_local(lkey); uint64_t ret; assert(data != NULL); @@ -637,22 +630,22 @@ void ossl_rcu_assign_uptr(void **p, void **v) ATOMIC_STORE(pvoid, p, v, __ATOMIC_RELEASE); } -static CRYPTO_ONCE rcu_init_once = CRYPTO_ONCE_STATIC_INIT; - -CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers) +CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx) { struct rcu_lock_st *new; - if (!CRYPTO_THREAD_run_once(&rcu_init_once, ossl_rcu_init)) - return NULL; - if (num_writers < 1) num_writers = 1; + ctx = ossl_lib_ctx_get_concrete(ctx); + if (ctx == NULL) + return 0; + new = OPENSSL_zalloc(sizeof(*new)); if (new == NULL) return NULL; + new->ctx = ctx; pthread_mutex_init(&new->write_lock, NULL); pthread_mutex_init(&new->prior_lock, NULL); pthread_mutex_init(&new->alloc_lock, NULL); diff --git a/crypto/threads_win.c b/crypto/threads_win.c index 9aec5e972f..873b2bd78c 100644 --- a/crypto/threads_win.c +++ b/crypto/threads_win.c @@ -43,8 +43,6 @@ typedef struct { } CRYPTO_win_rwlock; # endif -static CRYPTO_THREAD_LOCAL rcu_thr_key; - # define READER_SHIFT 0 # define ID_SHIFT 32 # define READER_SIZE 32 @@ -92,6 +90,7 @@ struct rcu_thr_data { */ struct rcu_lock_st { struct rcu_cb_item *cb_items; + OSSL_LIB_CTX *ctx; uint32_t id_ctr; struct rcu_qp *qp_group; size_t group_count; @@ -106,26 +105,6 @@ struct rcu_lock_st { CRYPTO_CONDVAR *prior_signal; }; -/* - * Called on thread exit to free the pthread key - * associated with this thread, if any - */ -static void free_rcu_thr_data(void *ptr) -{ - struct rcu_thr_data *data = - (struct rcu_thr_data *)CRYPTO_THREAD_get_local(&rcu_thr_key); - - OPENSSL_free(data); - CRYPTO_THREAD_set_local(&rcu_thr_key, NULL); -} - - -static void ossl_rcu_init(void) -{ - CRYPTO_THREAD_init_local(&rcu_thr_key, NULL); - ossl_init_thread_start(NULL, NULL, free_rcu_thr_data); -} - static struct rcu_qp *allocate_new_qp_group(struct rcu_lock_st *lock, int count) { @@ -136,23 +115,23 @@ static struct rcu_qp *allocate_new_qp_group(struct rcu_lock_st *lock, return new; } -static CRYPTO_ONCE rcu_init_once = CRYPTO_ONCE_STATIC_INIT; - -CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers) +CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx) { struct rcu_lock_st *new; - if (!CRYPTO_THREAD_run_once(&rcu_init_once, ossl_rcu_init)) - return NULL; - if (num_writers < 1) num_writers = 1; + ctx = ossl_lib_ctx_get_concrete(ctx); + if (ctx == NULL) + return 0; + new = OPENSSL_zalloc(sizeof(*new)); if (new == NULL) return NULL; + new->ctx = ctx; new->write_lock = ossl_crypto_mutex_new(); new->alloc_signal = ossl_crypto_condvar_new(); new->prior_signal = ossl_crypto_condvar_new(); @@ -205,22 +184,32 @@ static inline struct rcu_qp *get_hold_current_qp(CRYPTO_RCU_LOCK *lock) return &lock->qp_group[qp_idx]; } +static void ossl_rcu_free_local_data(void *arg) +{ + OSSL_LIB_CTX *ctx = arg; + CRYPTO_THREAD_LOCAL *lkey = ossl_lib_ctx_get_rcukey(ctx); + struct rcu_thr_data *data = CRYPTO_THREAD_get_local(lkey); + OPENSSL_free(data); +} + void ossl_rcu_read_lock(CRYPTO_RCU_LOCK *lock) { struct rcu_thr_data *data; int i; int available_qp = -1; + CRYPTO_THREAD_LOCAL *lkey = ossl_lib_ctx_get_rcukey(lock->ctx); /* * we're going to access current_qp here so ask the * processor to fetch it */ - data = CRYPTO_THREAD_get_local(&rcu_thr_key); + data = CRYPTO_THREAD_get_local(lkey); if (data == NULL) { data = OPENSSL_zalloc(sizeof(*data)); OPENSSL_assert(data != NULL); - CRYPTO_THREAD_set_local(&rcu_thr_key, data); + CRYPTO_THREAD_set_local(lkey, data); + ossl_init_thread_start(NULL, lock->ctx, ossl_rcu_free_local_data); } for (i = 0; i < MAX_QPS; i++) { @@ -253,7 +242,8 @@ void ossl_rcu_write_unlock(CRYPTO_RCU_LOCK *lock) void ossl_rcu_read_unlock(CRYPTO_RCU_LOCK *lock) { - struct rcu_thr_data *data = CRYPTO_THREAD_get_local(&rcu_thr_key); + CRYPTO_THREAD_LOCAL *lkey = ossl_lib_ctx_get_rcukey(lock->ctx); + struct rcu_thr_data *data = CRYPTO_THREAD_get_local(lkey); int i; LONG64 ret; diff --git a/doc/internal/man3/ossl_rcu_lock_new.pod b/doc/internal/man3/ossl_rcu_lock_new.pod index 7b82f6bbd0..57b5e4d73d 100644 --- a/doc/internal/man3/ossl_rcu_lock_new.pod +++ b/doc/internal/man3/ossl_rcu_lock_new.pod @@ -13,7 +13,7 @@ ossl_rcu_assign_uptr =head1 SYNOPSIS - CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers); + CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx); void ossl_rcu_read_lock(CRYPTO_RCU_LOCK *lock); void ossl_rcu_write_lock(CRYPTO_RCU_LOCK *lock); void ossl_rcu_write_unlock(CRYPTO_RCU_LOCK *lock); @@ -65,7 +65,8 @@ ossl_rcu_lock_new() allocates a new RCU lock. The I param indicates the number of write side threads which may execute ossl_synchronize_rcu() in parallel. The value must be at least 1, but may be larger to obtain increased write side throughput at the cost of additional -internal memory usage. A value of 1 is generally recommended. +internal memory usage. A value of 1 is generally recommended. The I +parameter references the library context in which the lock is allocated. =item * diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h index 64851fd8ed..6c2ac47275 100644 --- a/include/internal/cryptlib.h +++ b/include/internal/cryptlib.h @@ -130,6 +130,7 @@ void ossl_lib_ctx_default_deinit(void); OSSL_EX_DATA_GLOBAL *ossl_lib_ctx_get_ex_data_global(OSSL_LIB_CTX *ctx); const char *ossl_lib_ctx_get_descriptor(OSSL_LIB_CTX *libctx); +CRYPTO_THREAD_LOCAL *ossl_lib_ctx_get_rcukey(OSSL_LIB_CTX *libctx); OSSL_LIB_CTX *ossl_crypto_ex_data_get_ossl_lib_ctx(const CRYPTO_EX_DATA *ad); int ossl_crypto_new_ex_data_ex(OSSL_LIB_CTX *ctx, int class_index, void *obj, diff --git a/include/internal/rcu.h b/include/internal/rcu.h index 7716a1c7f2..90160e8da7 100644 --- a/include/internal/rcu.h +++ b/include/internal/rcu.h @@ -11,11 +11,13 @@ # define OPENSSL_RCU_H # pragma once +#include "crypto/context.h" + typedef void (*rcu_cb_fn)(void *data); typedef struct rcu_lock_st CRYPTO_RCU_LOCK; -CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers); +CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx); void ossl_rcu_lock_free(CRYPTO_RCU_LOCK *lock); void ossl_rcu_read_lock(CRYPTO_RCU_LOCK *lock); void ossl_rcu_write_lock(CRYPTO_RCU_LOCK *lock); diff --git a/test/threadstest.c b/test/threadstest.c index 74bac08be4..c208c37d0a 100644 --- a/test/threadstest.c +++ b/test/threadstest.c @@ -420,7 +420,7 @@ static int _torture_rcu(void) writer2_done = 0; rcu_torture_result = 1; - rcu_lock = ossl_rcu_lock_new(1); + rcu_lock = ossl_rcu_lock_new(1, NULL); TEST_info("Staring rcu torture"); t1 = ossl_time_now(); diff --git a/test/threadstest.h b/test/threadstest.h index 8bdedd7052..3125cec378 100644 --- a/test/threadstest.h +++ b/test/threadstest.h @@ -65,6 +65,7 @@ static void *thread_run(void *arg) *(void **) (&f) = arg; f(); + OPENSSL_thread_stop(); return NULL; }