summaryrefslogtreecommitdiffstats
path: root/crypto/initthread.c
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2019-05-24 17:52:17 +0100
committerMatt Caswell <matt@openssl.org>2019-06-17 15:32:54 +0100
commit72592b866492b84ba5ca1251d1a45875764c7b27 (patch)
tree9dc9caaed0e18026f87ab681de307b39f1e66dcc /crypto/initthread.c
parent242f84d06aca7030b2bd52043c39b0cb80c4fec6 (diff)
Split thread intialisation and handling out of init.c
We're going to need some of these functions in the FIPS module, but most of the rest of the code in init.c is not needed. Therefore we split it out. Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/9040)
Diffstat (limited to 'crypto/initthread.c')
-rw-r--r--crypto/initthread.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/crypto/initthread.c b/crypto/initthread.c
new file mode 100644
index 0000000000..6e56d47338
--- /dev/null
+++ b/crypto/initthread.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/crypto.h>
+#include "internal/cryptlib_int.h"
+
+typedef struct thread_event_handler_st THREAD_EVENT_HANDLER;
+struct thread_event_handler_st {
+ OPENSSL_CTX *ctx;
+ ossl_thread_stop_handler_fn handfn;
+ THREAD_EVENT_HANDLER *next;
+};
+
+/*
+ * Since per-thread-specific-data destructors are not universally
+ * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
+ * is assumed to have destructor associated. And then an effort is made
+ * to call this single destructor on non-pthread platform[s].
+ *
+ * Initial value is "impossible". It is used as guard value to shortcut
+ * destructor for threads terminating before libcrypto is initialized or
+ * after it's de-initialized. Access to the key doesn't have to be
+ * serialized for the said threads, because they didn't use libcrypto
+ * and it doesn't matter if they pick "impossible" or derefernce real
+ * key value and pull NULL past initialization in the first thread that
+ * intends to use libcrypto.
+ */
+static union {
+ long sane;
+ CRYPTO_THREAD_LOCAL value;
+} destructor_key = { -1 };
+
+static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands);
+
+static void ossl_init_thread_destructor(void *hands)
+{
+ ossl_init_thread_stop((THREAD_EVENT_HANDLER **)hands);
+}
+
+int init_thread(void)
+{
+
+ if (!CRYPTO_THREAD_init_local(&destructor_key.value,
+ ossl_init_thread_destructor))
+ return 0;
+
+ return 1;
+}
+
+void cleanup_thread(void)
+{
+ CRYPTO_THREAD_cleanup_local(&destructor_key.value);
+ destructor_key.sane = -1;
+}
+
+static THREAD_EVENT_HANDLER **ossl_init_get_thread_local(int alloc)
+{
+ THREAD_EVENT_HANDLER **hands =
+ CRYPTO_THREAD_get_local(&destructor_key.value);
+
+ if (alloc) {
+ if (hands == NULL
+ && (hands = OPENSSL_zalloc(sizeof(*hands))) != NULL
+ && !CRYPTO_THREAD_set_local(&destructor_key.value, hands)) {
+ OPENSSL_free(hands);
+ return NULL;
+ }
+ } else {
+ CRYPTO_THREAD_set_local(&destructor_key.value, NULL);
+ }
+
+ return hands;
+}
+
+static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands)
+{
+ THREAD_EVENT_HANDLER *curr, *prev = NULL;
+
+ /* Can't do much about this */
+ if (hands == NULL)
+ return;
+
+ curr = *hands;
+ while (curr != NULL) {
+ curr->handfn(curr->ctx);
+ prev = curr;
+ curr = curr->next;
+ OPENSSL_free(prev);
+ }
+
+ OPENSSL_free(hands);
+}
+
+void OPENSSL_thread_stop(void)
+{
+ if (destructor_key.sane != -1)
+ ossl_init_thread_stop(ossl_init_get_thread_local(0));
+}
+
+int ossl_init_thread_start(OPENSSL_CTX *ctx, ossl_thread_stop_handler_fn handfn)
+{
+ THREAD_EVENT_HANDLER **hands;
+ THREAD_EVENT_HANDLER *hand;
+
+ if (!OPENSSL_init_crypto(0, NULL))
+ return 0;
+
+ hands = ossl_init_get_thread_local(1);
+
+ if (hands == NULL)
+ return 0;
+
+ hand = OPENSSL_malloc(sizeof(*hand));
+ if (hand == NULL)
+ return 0;
+
+ hand->handfn = handfn;
+ hand->ctx = ctx;
+ hand->next = *hands;
+ *hands = hand;
+
+ return 1;
+}