Refactor init_get_thread_local to be more understandable

We currently have a single function that does thread_local key
allocation/cleanup/fetching for our OSSL_init_thread_start/stop apis,
and its pretty confusing.  Wrap it up in some helper functions to make
it more clear at the call sites what we're trying to do.

Reviewed-by: Saša Nedvědický <sashan@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/27794)
This commit is contained in:
Neil Horman 2025-06-18 11:16:47 -04:00
parent 5466197f16
commit d259b8b855
1 changed files with 85 additions and 81 deletions

View File

@ -83,70 +83,6 @@ static GLOBAL_TEVENT_REGISTER *get_global_tevent_register(void)
}
#endif
#ifndef FIPS_MODULE
static int init_thread_push_handlers(THREAD_EVENT_HANDLER **hands);
static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin);
static void init_thread_destructor(void *hands);
static int init_thread_deregister(void *arg, int all);
#endif
static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands);
#ifndef FIPS_MODULE
static THREAD_EVENT_HANDLER **
init_get_thread_local(CRYPTO_THREAD_LOCAL *local, int alloc, int keep)
{
THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local(local);
if (alloc) {
if (hands == NULL) {
if ((hands = OPENSSL_zalloc(sizeof(*hands))) == NULL)
return NULL;
if (!CRYPTO_THREAD_set_local(local, hands)) {
OPENSSL_free(hands);
return NULL;
}
if (!init_thread_push_handlers(hands)) {
CRYPTO_THREAD_set_local(local, NULL);
OPENSSL_free(hands);
return NULL;
}
}
} else if (!keep) {
CRYPTO_THREAD_set_local(local, NULL);
}
return hands;
}
#else
static THREAD_EVENT_HANDLER **
init_get_thread_local_ex(OSSL_LIB_CTX *ctx, int alloc, int keep)
{
THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, ctx);
if (alloc) {
if (hands == NULL) {
if ((hands = OPENSSL_zalloc(sizeof(*hands))) == NULL)
return NULL;
if (!CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, ctx, hands)) {
OPENSSL_free(hands);
return NULL;
}
}
} else if (!keep) {
CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, ctx, NULL);
}
return hands;
}
#endif
#ifndef FIPS_MODULE
/*
* Since per-thread-specific-data destructors are not universally
@ -167,6 +103,81 @@ static union {
CRYPTO_THREAD_LOCAL value;
} destructor_key = { -1 };
static int init_thread_push_handlers(THREAD_EVENT_HANDLER **hands);
static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin);
static void init_thread_destructor(void *hands);
static int init_thread_deregister(void *arg, int all);
#endif
static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands);
static THREAD_EVENT_HANDLER ** get_thread_event_handler(OSSL_LIB_CTX *ctx)
{
#ifdef FIPS_MODULE
return CRYPTO_THREAD_get_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, ctx);
#else
if (destructor_key.sane != -1)
return CRYPTO_THREAD_get_local(&destructor_key.value);
return NULL;
#endif
}
static int set_thread_event_handler(OSSL_LIB_CTX *ctx, THREAD_EVENT_HANDLER **hands)
{
#ifdef FIPS_MODULE
return CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, ctx, hands);
#else
if (destructor_key.sane != -1)
return CRYPTO_THREAD_set_local(&destructor_key.value, hands);
return 0;
#endif
}
static THREAD_EVENT_HANDLER **
init_manage_thread_local(OSSL_LIB_CTX *ctx, int alloc, int keep)
{
THREAD_EVENT_HANDLER **hands = get_thread_event_handler(ctx);
if (alloc) {
if (hands == NULL) {
if ((hands = OPENSSL_zalloc(sizeof(*hands))) == NULL)
return NULL;
if (!set_thread_event_handler(ctx, hands)) {
OPENSSL_free(hands);
return NULL;
}
#ifndef FIPS_MODULE
if (!init_thread_push_handlers(hands)) {
set_thread_event_handler(ctx, NULL);
OPENSSL_free(hands);
return NULL;
}
#endif
}
} else if (!keep) {
set_thread_event_handler(ctx, NULL);
}
return hands;
}
static ossl_inline THREAD_EVENT_HANDLER **init_fetch_clear_thread_local(OSSL_LIB_CTX *ctx)
{
return init_manage_thread_local(ctx, 0, 0);
}
static ossl_inline ossl_unused THREAD_EVENT_HANDLER **init_fetch_thread_local(OSSL_LIB_CTX *ctx)
{
return init_manage_thread_local(ctx, 0, 1);
}
static ossl_inline THREAD_EVENT_HANDLER **init_fetch_alloc_thread_local(OSSL_LIB_CTX *ctx)
{
return init_manage_thread_local(ctx, 1, 0);
}
#ifndef FIPS_MODULE
/*
* The thread event handler list is a thread specific linked list
* of callback functions which are invoked in list order by the
@ -255,8 +266,8 @@ void OPENSSL_thread_stop_ex(OSSL_LIB_CTX *ctx)
void OPENSSL_thread_stop(void)
{
if (destructor_key.sane != -1) {
THREAD_EVENT_HANDLER **hands
= init_get_thread_local(&destructor_key.value, 0, 0);
THREAD_EVENT_HANDLER **hands = init_fetch_clear_thread_local(NULL);
init_thread_stop(NULL, hands);
init_thread_remove_handlers(hands);
@ -267,8 +278,8 @@ void OPENSSL_thread_stop(void)
void ossl_ctx_thread_stop(OSSL_LIB_CTX *ctx)
{
if (destructor_key.sane != -1) {
THREAD_EVENT_HANDLER **hands
= init_get_thread_local(&destructor_key.value, 0, 1);
THREAD_EVENT_HANDLER **hands = init_fetch_thread_local(ctx);
init_thread_stop(ctx, hands);
}
}
@ -325,7 +336,7 @@ void ossl_ctx_thread_stop(OSSL_LIB_CTX *ctx)
{
THREAD_EVENT_HANDLER **hands;
hands = init_get_thread_local_ex(ctx, 0, 0);
hands = init_fetch_clear_thread_local(ctx);
init_thread_stop(ctx, hands);
OPENSSL_free(hands);
}
@ -380,26 +391,19 @@ int ossl_init_thread_start(const void *index, void *arg,
{
THREAD_EVENT_HANDLER **hands;
THREAD_EVENT_HANDLER *hand;
OSSL_LIB_CTX *ctx = NULL;
#ifdef FIPS_MODULE
OSSL_LIB_CTX *ctx = arg;
/*
* In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination
* of OSSL_LIB_CTX and thread. This is because in FIPS mode each
* OSSL_LIB_CTX gets informed about thread stop events individually.
*/
hands = init_get_thread_local_ex(ctx, 1, 0);
#else
/*
* Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
* thread, but may hold multiple OSSL_LIB_CTXs. We only get told about
* thread stop events globally, so we have to ensure all affected
* OSSL_LIB_CTXs are informed.
*/
CRYPTO_THREAD_LOCAL *local = &destructor_key.value;
hands = init_get_thread_local(local, 1, 0);
ctx = arg;
#endif
hands = init_fetch_alloc_thread_local(ctx);
if (hands == NULL)
return 0;