2 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 #include <openssl/crypto.h>
11 #include "internal/cryptlib_int.h"
13 typedef struct thread_event_handler_st THREAD_EVENT_HANDLER;
14 struct thread_event_handler_st {
16 ossl_thread_stop_handler_fn handfn;
17 THREAD_EVENT_HANDLER *next;
21 * Since per-thread-specific-data destructors are not universally
22 * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
23 * is assumed to have destructor associated. And then an effort is made
24 * to call this single destructor on non-pthread platform[s].
26 * Initial value is "impossible". It is used as guard value to shortcut
27 * destructor for threads terminating before libcrypto is initialized or
28 * after it's de-initialized. Access to the key doesn't have to be
29 * serialized for the said threads, because they didn't use libcrypto
30 * and it doesn't matter if they pick "impossible" or derefernce real
31 * key value and pull NULL past initialization in the first thread that
32 * intends to use libcrypto.
36 CRYPTO_THREAD_LOCAL value;
37 } destructor_key = { -1 };
39 static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands);
41 static void ossl_init_thread_destructor(void *hands)
43 ossl_init_thread_stop((THREAD_EVENT_HANDLER **)hands);
49 if (!CRYPTO_THREAD_init_local(&destructor_key.value,
50 ossl_init_thread_destructor))
56 void cleanup_thread(void)
58 CRYPTO_THREAD_cleanup_local(&destructor_key.value);
59 destructor_key.sane = -1;
62 static THREAD_EVENT_HANDLER **ossl_init_get_thread_local(int alloc)
64 THREAD_EVENT_HANDLER **hands =
65 CRYPTO_THREAD_get_local(&destructor_key.value);
69 && (hands = OPENSSL_zalloc(sizeof(*hands))) != NULL
70 && !CRYPTO_THREAD_set_local(&destructor_key.value, hands)) {
75 CRYPTO_THREAD_set_local(&destructor_key.value, NULL);
81 static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands)
83 THREAD_EVENT_HANDLER *curr, *prev = NULL;
85 /* Can't do much about this */
90 while (curr != NULL) {
91 curr->handfn(curr->ctx);
100 void OPENSSL_thread_stop(void)
102 if (destructor_key.sane != -1)
103 ossl_init_thread_stop(ossl_init_get_thread_local(0));
106 int ossl_init_thread_start(OPENSSL_CTX *ctx, ossl_thread_stop_handler_fn handfn)
108 THREAD_EVENT_HANDLER **hands;
109 THREAD_EVENT_HANDLER *hand;
111 if (!OPENSSL_init_crypto(0, NULL))
114 hands = ossl_init_get_thread_local(1);
119 hand = OPENSSL_malloc(sizeof(*hand));
123 hand->handfn = handfn;