xref: /netbsd-src/crypto/external/bsd/openssl/dist/crypto/initthread.c (revision b0d1725196a7921d003d2c66a14f186abda4176b)
1*b0d17251Schristos /*
2*b0d17251Schristos  * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
3*b0d17251Schristos  *
4*b0d17251Schristos  * Licensed under the Apache License 2.0 (the "License").  You may not use
5*b0d17251Schristos  * this file except in compliance with the License.  You can obtain a copy
6*b0d17251Schristos  * in the file LICENSE in the source distribution or at
7*b0d17251Schristos  * https://www.openssl.org/source/license.html
8*b0d17251Schristos  */
9*b0d17251Schristos 
10*b0d17251Schristos #include <openssl/crypto.h>
11*b0d17251Schristos #include <openssl/core_dispatch.h>
12*b0d17251Schristos #include "crypto/cryptlib.h"
13*b0d17251Schristos #include "prov/providercommon.h"
14*b0d17251Schristos #include "internal/thread_once.h"
15*b0d17251Schristos 
16*b0d17251Schristos #ifdef FIPS_MODULE
17*b0d17251Schristos #include "prov/provider_ctx.h"
18*b0d17251Schristos 
19*b0d17251Schristos /*
20*b0d17251Schristos  * Thread aware code may want to be told about thread stop events. We register
21*b0d17251Schristos  * to hear about those thread stop events when we see a new thread has started.
22*b0d17251Schristos  * We call the ossl_init_thread_start function to do that. In the FIPS provider
23*b0d17251Schristos  * we have our own copy of ossl_init_thread_start, which cascades notifications
24*b0d17251Schristos  * about threads stopping from libcrypto to all the code in the FIPS provider
25*b0d17251Schristos  * that needs to know about it.
26*b0d17251Schristos  *
27*b0d17251Schristos  * The FIPS provider tells libcrypto about which threads it is interested in
28*b0d17251Schristos  * by calling "c_thread_start" which is a function pointer created during
29*b0d17251Schristos  * provider initialisation (i.e. OSSL_init_provider).
30*b0d17251Schristos  */
31*b0d17251Schristos extern OSSL_FUNC_core_thread_start_fn *c_thread_start;
32*b0d17251Schristos #endif
33*b0d17251Schristos 
34*b0d17251Schristos typedef struct thread_event_handler_st THREAD_EVENT_HANDLER;
35*b0d17251Schristos struct thread_event_handler_st {
36*b0d17251Schristos #ifndef FIPS_MODULE
37*b0d17251Schristos     const void *index;
38*b0d17251Schristos #endif
39*b0d17251Schristos     void *arg;
40*b0d17251Schristos     OSSL_thread_stop_handler_fn handfn;
41*b0d17251Schristos     THREAD_EVENT_HANDLER *next;
42*b0d17251Schristos };
43*b0d17251Schristos 
44*b0d17251Schristos #ifndef FIPS_MODULE
45*b0d17251Schristos DEFINE_SPECIAL_STACK_OF(THREAD_EVENT_HANDLER_PTR, THREAD_EVENT_HANDLER *)
46*b0d17251Schristos 
47*b0d17251Schristos typedef struct global_tevent_register_st GLOBAL_TEVENT_REGISTER;
48*b0d17251Schristos struct global_tevent_register_st {
49*b0d17251Schristos     STACK_OF(THREAD_EVENT_HANDLER_PTR) *skhands;
50*b0d17251Schristos     CRYPTO_RWLOCK *lock;
51*b0d17251Schristos };
52*b0d17251Schristos 
53*b0d17251Schristos static GLOBAL_TEVENT_REGISTER *glob_tevent_reg = NULL;
54*b0d17251Schristos 
55*b0d17251Schristos static CRYPTO_ONCE tevent_register_runonce = CRYPTO_ONCE_STATIC_INIT;
56*b0d17251Schristos 
DEFINE_RUN_ONCE_STATIC(create_global_tevent_register)57*b0d17251Schristos DEFINE_RUN_ONCE_STATIC(create_global_tevent_register)
58*b0d17251Schristos {
59*b0d17251Schristos     glob_tevent_reg = OPENSSL_zalloc(sizeof(*glob_tevent_reg));
60*b0d17251Schristos     if (glob_tevent_reg == NULL)
61*b0d17251Schristos         return 0;
62*b0d17251Schristos 
63*b0d17251Schristos     glob_tevent_reg->skhands = sk_THREAD_EVENT_HANDLER_PTR_new_null();
64*b0d17251Schristos     glob_tevent_reg->lock = CRYPTO_THREAD_lock_new();
65*b0d17251Schristos     if (glob_tevent_reg->skhands == NULL || glob_tevent_reg->lock == NULL) {
66*b0d17251Schristos         sk_THREAD_EVENT_HANDLER_PTR_free(glob_tevent_reg->skhands);
67*b0d17251Schristos         CRYPTO_THREAD_lock_free(glob_tevent_reg->lock);
68*b0d17251Schristos         OPENSSL_free(glob_tevent_reg);
69*b0d17251Schristos         glob_tevent_reg = NULL;
70*b0d17251Schristos         return 0;
71*b0d17251Schristos     }
72*b0d17251Schristos 
73*b0d17251Schristos     return 1;
74*b0d17251Schristos }
75*b0d17251Schristos 
get_global_tevent_register(void)76*b0d17251Schristos static GLOBAL_TEVENT_REGISTER *get_global_tevent_register(void)
77*b0d17251Schristos {
78*b0d17251Schristos     if (!RUN_ONCE(&tevent_register_runonce, create_global_tevent_register))
79*b0d17251Schristos         return NULL;
80*b0d17251Schristos     return glob_tevent_reg;
81*b0d17251Schristos }
82*b0d17251Schristos #endif
83*b0d17251Schristos 
84*b0d17251Schristos #ifndef FIPS_MODULE
85*b0d17251Schristos static int  init_thread_push_handlers(THREAD_EVENT_HANDLER **hands);
86*b0d17251Schristos static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin);
87*b0d17251Schristos static void init_thread_destructor(void *hands);
88*b0d17251Schristos static int  init_thread_deregister(void *arg, int all);
89*b0d17251Schristos #endif
90*b0d17251Schristos static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands);
91*b0d17251Schristos 
92*b0d17251Schristos static THREAD_EVENT_HANDLER **
init_get_thread_local(CRYPTO_THREAD_LOCAL * local,int alloc,int keep)93*b0d17251Schristos init_get_thread_local(CRYPTO_THREAD_LOCAL *local, int alloc, int keep)
94*b0d17251Schristos {
95*b0d17251Schristos     THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local(local);
96*b0d17251Schristos 
97*b0d17251Schristos     if (alloc) {
98*b0d17251Schristos         if (hands == NULL) {
99*b0d17251Schristos 
100*b0d17251Schristos             if ((hands = OPENSSL_zalloc(sizeof(*hands))) == NULL)
101*b0d17251Schristos                 return NULL;
102*b0d17251Schristos 
103*b0d17251Schristos             if (!CRYPTO_THREAD_set_local(local, hands)) {
104*b0d17251Schristos                 OPENSSL_free(hands);
105*b0d17251Schristos                 return NULL;
106*b0d17251Schristos             }
107*b0d17251Schristos 
108*b0d17251Schristos #ifndef FIPS_MODULE
109*b0d17251Schristos             if (!init_thread_push_handlers(hands)) {
110*b0d17251Schristos                 CRYPTO_THREAD_set_local(local, NULL);
111*b0d17251Schristos                 OPENSSL_free(hands);
112*b0d17251Schristos                 return NULL;
113*b0d17251Schristos             }
114*b0d17251Schristos #endif
115*b0d17251Schristos         }
116*b0d17251Schristos     } else if (!keep) {
117*b0d17251Schristos         CRYPTO_THREAD_set_local(local, NULL);
118*b0d17251Schristos     }
119*b0d17251Schristos 
120*b0d17251Schristos     return hands;
121*b0d17251Schristos }
122*b0d17251Schristos 
123*b0d17251Schristos #ifndef FIPS_MODULE
124*b0d17251Schristos /*
125*b0d17251Schristos  * Since per-thread-specific-data destructors are not universally
126*b0d17251Schristos  * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
127*b0d17251Schristos  * is assumed to have destructor associated. And then an effort is made
128*b0d17251Schristos  * to call this single destructor on non-pthread platform[s].
129*b0d17251Schristos  *
130*b0d17251Schristos  * Initial value is "impossible". It is used as guard value to shortcut
131*b0d17251Schristos  * destructor for threads terminating before libcrypto is initialized or
132*b0d17251Schristos  * after it's de-initialized. Access to the key doesn't have to be
133*b0d17251Schristos  * serialized for the said threads, because they didn't use libcrypto
134*b0d17251Schristos  * and it doesn't matter if they pick "impossible" or dereference real
135*b0d17251Schristos  * key value and pull NULL past initialization in the first thread that
136*b0d17251Schristos  * intends to use libcrypto.
137*b0d17251Schristos  */
138*b0d17251Schristos static union {
139*b0d17251Schristos     long sane;
140*b0d17251Schristos     CRYPTO_THREAD_LOCAL value;
141*b0d17251Schristos } destructor_key = { -1 };
142*b0d17251Schristos 
143*b0d17251Schristos /*
144*b0d17251Schristos  * The thread event handler list is a thread specific linked list
145*b0d17251Schristos  * of callback functions which are invoked in list order by the
146*b0d17251Schristos  * current thread in case of certain events. (Currently, there is
147*b0d17251Schristos  * only one type of event, the 'thread stop' event.)
148*b0d17251Schristos  *
149*b0d17251Schristos  * We also keep a global reference to that linked list, so that we
150*b0d17251Schristos  * can deregister handlers if necessary before all the threads are
151*b0d17251Schristos  * stopped.
152*b0d17251Schristos  */
init_thread_push_handlers(THREAD_EVENT_HANDLER ** hands)153*b0d17251Schristos static int init_thread_push_handlers(THREAD_EVENT_HANDLER **hands)
154*b0d17251Schristos {
155*b0d17251Schristos     int ret;
156*b0d17251Schristos     GLOBAL_TEVENT_REGISTER *gtr;
157*b0d17251Schristos 
158*b0d17251Schristos     gtr = get_global_tevent_register();
159*b0d17251Schristos     if (gtr == NULL)
160*b0d17251Schristos         return 0;
161*b0d17251Schristos 
162*b0d17251Schristos     if (!CRYPTO_THREAD_write_lock(gtr->lock))
163*b0d17251Schristos         return 0;
164*b0d17251Schristos     ret = (sk_THREAD_EVENT_HANDLER_PTR_push(gtr->skhands, hands) != 0);
165*b0d17251Schristos     CRYPTO_THREAD_unlock(gtr->lock);
166*b0d17251Schristos 
167*b0d17251Schristos     return ret;
168*b0d17251Schristos }
169*b0d17251Schristos 
init_thread_remove_handlers(THREAD_EVENT_HANDLER ** handsin)170*b0d17251Schristos static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin)
171*b0d17251Schristos {
172*b0d17251Schristos     GLOBAL_TEVENT_REGISTER *gtr;
173*b0d17251Schristos     int i;
174*b0d17251Schristos 
175*b0d17251Schristos     gtr = get_global_tevent_register();
176*b0d17251Schristos     if (gtr == NULL)
177*b0d17251Schristos         return;
178*b0d17251Schristos     if (!CRYPTO_THREAD_write_lock(gtr->lock))
179*b0d17251Schristos         return;
180*b0d17251Schristos     for (i = 0; i < sk_THREAD_EVENT_HANDLER_PTR_num(gtr->skhands); i++) {
181*b0d17251Schristos         THREAD_EVENT_HANDLER **hands
182*b0d17251Schristos             = sk_THREAD_EVENT_HANDLER_PTR_value(gtr->skhands, i);
183*b0d17251Schristos 
184*b0d17251Schristos         if (hands == handsin) {
185*b0d17251Schristos             sk_THREAD_EVENT_HANDLER_PTR_delete(gtr->skhands, i);
186*b0d17251Schristos             CRYPTO_THREAD_unlock(gtr->lock);
187*b0d17251Schristos             return;
188*b0d17251Schristos         }
189*b0d17251Schristos     }
190*b0d17251Schristos     CRYPTO_THREAD_unlock(gtr->lock);
191*b0d17251Schristos     return;
192*b0d17251Schristos }
193*b0d17251Schristos 
init_thread_destructor(void * hands)194*b0d17251Schristos static void init_thread_destructor(void *hands)
195*b0d17251Schristos {
196*b0d17251Schristos     init_thread_stop(NULL, (THREAD_EVENT_HANDLER **)hands);
197*b0d17251Schristos     init_thread_remove_handlers(hands);
198*b0d17251Schristos     OPENSSL_free(hands);
199*b0d17251Schristos }
200*b0d17251Schristos 
ossl_init_thread(void)201*b0d17251Schristos int ossl_init_thread(void)
202*b0d17251Schristos {
203*b0d17251Schristos     if (!CRYPTO_THREAD_init_local(&destructor_key.value,
204*b0d17251Schristos                                   init_thread_destructor))
205*b0d17251Schristos         return 0;
206*b0d17251Schristos 
207*b0d17251Schristos     return 1;
208*b0d17251Schristos }
209*b0d17251Schristos 
ossl_cleanup_thread(void)210*b0d17251Schristos void ossl_cleanup_thread(void)
211*b0d17251Schristos {
212*b0d17251Schristos     init_thread_deregister(NULL, 1);
213*b0d17251Schristos     CRYPTO_THREAD_cleanup_local(&destructor_key.value);
214*b0d17251Schristos     destructor_key.sane = -1;
215*b0d17251Schristos }
216*b0d17251Schristos 
OPENSSL_thread_stop_ex(OSSL_LIB_CTX * ctx)217*b0d17251Schristos void OPENSSL_thread_stop_ex(OSSL_LIB_CTX *ctx)
218*b0d17251Schristos {
219*b0d17251Schristos     ctx = ossl_lib_ctx_get_concrete(ctx);
220*b0d17251Schristos     /*
221*b0d17251Schristos      * It would be nice if we could figure out a way to do this on all threads
222*b0d17251Schristos      * that have used the OSSL_LIB_CTX when the context is freed. This is
223*b0d17251Schristos      * currently not possible due to the use of thread local variables.
224*b0d17251Schristos      */
225*b0d17251Schristos     ossl_ctx_thread_stop(ctx);
226*b0d17251Schristos }
227*b0d17251Schristos 
OPENSSL_thread_stop(void)228*b0d17251Schristos void OPENSSL_thread_stop(void)
229*b0d17251Schristos {
230*b0d17251Schristos     if (destructor_key.sane != -1) {
231*b0d17251Schristos         THREAD_EVENT_HANDLER **hands
232*b0d17251Schristos             = init_get_thread_local(&destructor_key.value, 0, 0);
233*b0d17251Schristos         init_thread_stop(NULL, hands);
234*b0d17251Schristos 
235*b0d17251Schristos         init_thread_remove_handlers(hands);
236*b0d17251Schristos         OPENSSL_free(hands);
237*b0d17251Schristos     }
238*b0d17251Schristos }
239*b0d17251Schristos 
ossl_ctx_thread_stop(OSSL_LIB_CTX * ctx)240*b0d17251Schristos void ossl_ctx_thread_stop(OSSL_LIB_CTX *ctx)
241*b0d17251Schristos {
242*b0d17251Schristos     if (destructor_key.sane != -1) {
243*b0d17251Schristos         THREAD_EVENT_HANDLER **hands
244*b0d17251Schristos             = init_get_thread_local(&destructor_key.value, 0, 1);
245*b0d17251Schristos         init_thread_stop(ctx, hands);
246*b0d17251Schristos     }
247*b0d17251Schristos }
248*b0d17251Schristos 
249*b0d17251Schristos #else
250*b0d17251Schristos 
thread_event_ossl_ctx_new(OSSL_LIB_CTX * libctx)251*b0d17251Schristos static void *thread_event_ossl_ctx_new(OSSL_LIB_CTX *libctx)
252*b0d17251Schristos {
253*b0d17251Schristos     THREAD_EVENT_HANDLER **hands = NULL;
254*b0d17251Schristos     CRYPTO_THREAD_LOCAL *tlocal = OPENSSL_zalloc(sizeof(*tlocal));
255*b0d17251Schristos 
256*b0d17251Schristos     if (tlocal == NULL)
257*b0d17251Schristos         return NULL;
258*b0d17251Schristos 
259*b0d17251Schristos     if (!CRYPTO_THREAD_init_local(tlocal,  NULL)) {
260*b0d17251Schristos         goto err;
261*b0d17251Schristos     }
262*b0d17251Schristos 
263*b0d17251Schristos     hands = OPENSSL_zalloc(sizeof(*hands));
264*b0d17251Schristos     if (hands == NULL)
265*b0d17251Schristos         goto err;
266*b0d17251Schristos 
267*b0d17251Schristos     if (!CRYPTO_THREAD_set_local(tlocal, hands))
268*b0d17251Schristos         goto err;
269*b0d17251Schristos 
270*b0d17251Schristos     return tlocal;
271*b0d17251Schristos  err:
272*b0d17251Schristos     OPENSSL_free(hands);
273*b0d17251Schristos     OPENSSL_free(tlocal);
274*b0d17251Schristos     return NULL;
275*b0d17251Schristos }
276*b0d17251Schristos 
thread_event_ossl_ctx_free(void * tlocal)277*b0d17251Schristos static void thread_event_ossl_ctx_free(void *tlocal)
278*b0d17251Schristos {
279*b0d17251Schristos     OPENSSL_free(tlocal);
280*b0d17251Schristos }
281*b0d17251Schristos 
282*b0d17251Schristos static const OSSL_LIB_CTX_METHOD thread_event_ossl_ctx_method = {
283*b0d17251Schristos     OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
284*b0d17251Schristos     thread_event_ossl_ctx_new,
285*b0d17251Schristos     thread_event_ossl_ctx_free,
286*b0d17251Schristos };
287*b0d17251Schristos 
ossl_arg_thread_stop(void * arg)288*b0d17251Schristos static void ossl_arg_thread_stop(void *arg)
289*b0d17251Schristos {
290*b0d17251Schristos     ossl_ctx_thread_stop((OSSL_LIB_CTX *)arg);
291*b0d17251Schristos }
292*b0d17251Schristos 
ossl_ctx_thread_stop(OSSL_LIB_CTX * ctx)293*b0d17251Schristos void ossl_ctx_thread_stop(OSSL_LIB_CTX *ctx)
294*b0d17251Schristos {
295*b0d17251Schristos     THREAD_EVENT_HANDLER **hands;
296*b0d17251Schristos     CRYPTO_THREAD_LOCAL *local
297*b0d17251Schristos         = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX,
298*b0d17251Schristos                                 &thread_event_ossl_ctx_method);
299*b0d17251Schristos 
300*b0d17251Schristos     if (local == NULL)
301*b0d17251Schristos         return;
302*b0d17251Schristos     hands = init_get_thread_local(local, 0, 0);
303*b0d17251Schristos     init_thread_stop(ctx, hands);
304*b0d17251Schristos     OPENSSL_free(hands);
305*b0d17251Schristos }
306*b0d17251Schristos #endif /* FIPS_MODULE */
307*b0d17251Schristos 
308*b0d17251Schristos 
init_thread_stop(void * arg,THREAD_EVENT_HANDLER ** hands)309*b0d17251Schristos static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands)
310*b0d17251Schristos {
311*b0d17251Schristos     THREAD_EVENT_HANDLER *curr, *prev = NULL, *tmp;
312*b0d17251Schristos #ifndef FIPS_MODULE
313*b0d17251Schristos     GLOBAL_TEVENT_REGISTER *gtr;
314*b0d17251Schristos #endif
315*b0d17251Schristos 
316*b0d17251Schristos     /* Can't do much about this */
317*b0d17251Schristos     if (hands == NULL)
318*b0d17251Schristos         return;
319*b0d17251Schristos 
320*b0d17251Schristos #ifndef FIPS_MODULE
321*b0d17251Schristos     gtr = get_global_tevent_register();
322*b0d17251Schristos     if (gtr == NULL)
323*b0d17251Schristos         return;
324*b0d17251Schristos 
325*b0d17251Schristos     if (!CRYPTO_THREAD_write_lock(gtr->lock))
326*b0d17251Schristos         return;
327*b0d17251Schristos #endif
328*b0d17251Schristos 
329*b0d17251Schristos     curr = *hands;
330*b0d17251Schristos     while (curr != NULL) {
331*b0d17251Schristos         if (arg != NULL && curr->arg != arg) {
332*b0d17251Schristos             prev = curr;
333*b0d17251Schristos             curr = curr->next;
334*b0d17251Schristos             continue;
335*b0d17251Schristos         }
336*b0d17251Schristos         curr->handfn(curr->arg);
337*b0d17251Schristos         if (prev == NULL)
338*b0d17251Schristos             *hands = curr->next;
339*b0d17251Schristos         else
340*b0d17251Schristos             prev->next = curr->next;
341*b0d17251Schristos 
342*b0d17251Schristos         tmp = curr;
343*b0d17251Schristos         curr = curr->next;
344*b0d17251Schristos 
345*b0d17251Schristos         OPENSSL_free(tmp);
346*b0d17251Schristos     }
347*b0d17251Schristos #ifndef FIPS_MODULE
348*b0d17251Schristos     CRYPTO_THREAD_unlock(gtr->lock);
349*b0d17251Schristos #endif
350*b0d17251Schristos }
351*b0d17251Schristos 
ossl_init_thread_start(const void * index,void * arg,OSSL_thread_stop_handler_fn handfn)352*b0d17251Schristos int ossl_init_thread_start(const void *index, void *arg,
353*b0d17251Schristos                            OSSL_thread_stop_handler_fn handfn)
354*b0d17251Schristos {
355*b0d17251Schristos     THREAD_EVENT_HANDLER **hands;
356*b0d17251Schristos     THREAD_EVENT_HANDLER *hand;
357*b0d17251Schristos #ifdef FIPS_MODULE
358*b0d17251Schristos     OSSL_LIB_CTX *ctx = arg;
359*b0d17251Schristos 
360*b0d17251Schristos     /*
361*b0d17251Schristos      * In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination
362*b0d17251Schristos      * of OSSL_LIB_CTX and thread. This is because in FIPS mode each
363*b0d17251Schristos      * OSSL_LIB_CTX gets informed about thread stop events individually.
364*b0d17251Schristos      */
365*b0d17251Schristos     CRYPTO_THREAD_LOCAL *local
366*b0d17251Schristos         = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX,
367*b0d17251Schristos                                 &thread_event_ossl_ctx_method);
368*b0d17251Schristos #else
369*b0d17251Schristos     /*
370*b0d17251Schristos      * Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
371*b0d17251Schristos      * thread, but may hold multiple OSSL_LIB_CTXs. We only get told about
372*b0d17251Schristos      * thread stop events globally, so we have to ensure all affected
373*b0d17251Schristos      * OSSL_LIB_CTXs are informed.
374*b0d17251Schristos      */
375*b0d17251Schristos     CRYPTO_THREAD_LOCAL *local = &destructor_key.value;
376*b0d17251Schristos #endif
377*b0d17251Schristos 
378*b0d17251Schristos     hands = init_get_thread_local(local, 1, 0);
379*b0d17251Schristos     if (hands == NULL)
380*b0d17251Schristos         return 0;
381*b0d17251Schristos 
382*b0d17251Schristos #ifdef FIPS_MODULE
383*b0d17251Schristos     if (*hands == NULL) {
384*b0d17251Schristos         /*
385*b0d17251Schristos          * We've not yet registered any handlers for this thread. We need to get
386*b0d17251Schristos          * libcrypto to tell us about later thread stop events. c_thread_start
387*b0d17251Schristos          * is a callback to libcrypto defined in fipsprov.c
388*b0d17251Schristos          */
389*b0d17251Schristos         if (!c_thread_start(FIPS_get_core_handle(ctx), ossl_arg_thread_stop,
390*b0d17251Schristos                             ctx))
391*b0d17251Schristos             return 0;
392*b0d17251Schristos     }
393*b0d17251Schristos #endif
394*b0d17251Schristos 
395*b0d17251Schristos     hand = OPENSSL_malloc(sizeof(*hand));
396*b0d17251Schristos     if (hand == NULL)
397*b0d17251Schristos         return 0;
398*b0d17251Schristos 
399*b0d17251Schristos     hand->handfn = handfn;
400*b0d17251Schristos     hand->arg = arg;
401*b0d17251Schristos #ifndef FIPS_MODULE
402*b0d17251Schristos     hand->index = index;
403*b0d17251Schristos #endif
404*b0d17251Schristos     hand->next = *hands;
405*b0d17251Schristos     *hands = hand;
406*b0d17251Schristos 
407*b0d17251Schristos     return 1;
408*b0d17251Schristos }
409*b0d17251Schristos 
410*b0d17251Schristos #ifndef FIPS_MODULE
init_thread_deregister(void * index,int all)411*b0d17251Schristos static int init_thread_deregister(void *index, int all)
412*b0d17251Schristos {
413*b0d17251Schristos     GLOBAL_TEVENT_REGISTER *gtr;
414*b0d17251Schristos     int i;
415*b0d17251Schristos 
416*b0d17251Schristos     gtr = get_global_tevent_register();
417*b0d17251Schristos     if (gtr == NULL)
418*b0d17251Schristos         return 0;
419*b0d17251Schristos     if (!all) {
420*b0d17251Schristos         if (!CRYPTO_THREAD_write_lock(gtr->lock))
421*b0d17251Schristos             return 0;
422*b0d17251Schristos     } else {
423*b0d17251Schristos         glob_tevent_reg = NULL;
424*b0d17251Schristos     }
425*b0d17251Schristos     for (i = 0; i < sk_THREAD_EVENT_HANDLER_PTR_num(gtr->skhands); i++) {
426*b0d17251Schristos         THREAD_EVENT_HANDLER **hands
427*b0d17251Schristos             = sk_THREAD_EVENT_HANDLER_PTR_value(gtr->skhands, i);
428*b0d17251Schristos         THREAD_EVENT_HANDLER *curr = NULL, *prev = NULL, *tmp;
429*b0d17251Schristos 
430*b0d17251Schristos         if (hands == NULL) {
431*b0d17251Schristos             if (!all)
432*b0d17251Schristos                 CRYPTO_THREAD_unlock(gtr->lock);
433*b0d17251Schristos             return 0;
434*b0d17251Schristos         }
435*b0d17251Schristos         curr = *hands;
436*b0d17251Schristos         while (curr != NULL) {
437*b0d17251Schristos             if (all || curr->index == index) {
438*b0d17251Schristos                 if (prev != NULL)
439*b0d17251Schristos                     prev->next = curr->next;
440*b0d17251Schristos                 else
441*b0d17251Schristos                     *hands = curr->next;
442*b0d17251Schristos                 tmp = curr;
443*b0d17251Schristos                 curr = curr->next;
444*b0d17251Schristos                 OPENSSL_free(tmp);
445*b0d17251Schristos                 continue;
446*b0d17251Schristos             }
447*b0d17251Schristos             prev = curr;
448*b0d17251Schristos             curr = curr->next;
449*b0d17251Schristos         }
450*b0d17251Schristos         if (all)
451*b0d17251Schristos             OPENSSL_free(hands);
452*b0d17251Schristos     }
453*b0d17251Schristos     if (all) {
454*b0d17251Schristos         CRYPTO_THREAD_lock_free(gtr->lock);
455*b0d17251Schristos         sk_THREAD_EVENT_HANDLER_PTR_free(gtr->skhands);
456*b0d17251Schristos         OPENSSL_free(gtr);
457*b0d17251Schristos     } else {
458*b0d17251Schristos         CRYPTO_THREAD_unlock(gtr->lock);
459*b0d17251Schristos     }
460*b0d17251Schristos     return 1;
461*b0d17251Schristos }
462*b0d17251Schristos 
ossl_init_thread_deregister(void * index)463*b0d17251Schristos int ossl_init_thread_deregister(void *index)
464*b0d17251Schristos {
465*b0d17251Schristos     return init_thread_deregister(index, 0);
466*b0d17251Schristos }
467*b0d17251Schristos #endif
468