xref: /freebsd/crypto/krb5/src/util/support/threads.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* util/support/threads.c - Portable thread support */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright 2004,2005,2006,2007,2008 by the Massachusetts Institute of
5*7f2fe78bSCy Schubert  * Technology.  All Rights Reserved.
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert  *   require a specific license from the United States Government.
9*7f2fe78bSCy Schubert  *   It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert  *   export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert  *
12*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert  * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert  * permission.  Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert  * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert  * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert  * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
24*7f2fe78bSCy Schubert  * or implied warranty.
25*7f2fe78bSCy Schubert  */
26*7f2fe78bSCy Schubert 
27*7f2fe78bSCy Schubert #define THREAD_SUPPORT_IMPL
28*7f2fe78bSCy Schubert #include "k5-platform.h"
29*7f2fe78bSCy Schubert #include "k5-thread.h"
30*7f2fe78bSCy Schubert #include "supp-int.h"
31*7f2fe78bSCy Schubert 
32*7f2fe78bSCy Schubert MAKE_INIT_FUNCTION(krb5int_thread_support_init);
33*7f2fe78bSCy Schubert MAKE_FINI_FUNCTION(krb5int_thread_support_fini);
34*7f2fe78bSCy Schubert 
35*7f2fe78bSCy Schubert /* This function used to be referenced from elsewhere in the tree, but is now
36*7f2fe78bSCy Schubert  * only used internally.  Keep it linker-visible for now. */
37*7f2fe78bSCy Schubert int krb5int_pthread_loaded(void);
38*7f2fe78bSCy Schubert 
39*7f2fe78bSCy Schubert #ifndef ENABLE_THREADS /* no thread support */
40*7f2fe78bSCy Schubert 
41*7f2fe78bSCy Schubert static void (*destructors[K5_KEY_MAX])(void *);
42*7f2fe78bSCy Schubert struct tsd_block { void *values[K5_KEY_MAX]; };
43*7f2fe78bSCy Schubert static struct tsd_block tsd_no_threads;
44*7f2fe78bSCy Schubert static unsigned char destructors_set[K5_KEY_MAX];
45*7f2fe78bSCy Schubert 
krb5int_pthread_loaded(void)46*7f2fe78bSCy Schubert int krb5int_pthread_loaded (void)
47*7f2fe78bSCy Schubert {
48*7f2fe78bSCy Schubert     return 0;
49*7f2fe78bSCy Schubert }
50*7f2fe78bSCy Schubert 
51*7f2fe78bSCy Schubert #elif defined(_WIN32)
52*7f2fe78bSCy Schubert 
53*7f2fe78bSCy Schubert static DWORD tls_idx;
54*7f2fe78bSCy Schubert static CRITICAL_SECTION key_lock;
55*7f2fe78bSCy Schubert struct tsd_block {
56*7f2fe78bSCy Schubert     void *values[K5_KEY_MAX];
57*7f2fe78bSCy Schubert };
58*7f2fe78bSCy Schubert static void (*destructors[K5_KEY_MAX])(void *);
59*7f2fe78bSCy Schubert static unsigned char destructors_set[K5_KEY_MAX];
60*7f2fe78bSCy Schubert 
krb5int_thread_detach_hook(void)61*7f2fe78bSCy Schubert void krb5int_thread_detach_hook (void)
62*7f2fe78bSCy Schubert {
63*7f2fe78bSCy Schubert     /* XXX Memory leak here!
64*7f2fe78bSCy Schubert        Need to destroy all TLS objects we know about for this thread.  */
65*7f2fe78bSCy Schubert     struct tsd_block *t;
66*7f2fe78bSCy Schubert     int i, err;
67*7f2fe78bSCy Schubert 
68*7f2fe78bSCy Schubert     err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
69*7f2fe78bSCy Schubert     if (err)
70*7f2fe78bSCy Schubert         return;
71*7f2fe78bSCy Schubert 
72*7f2fe78bSCy Schubert     t = TlsGetValue(tls_idx);
73*7f2fe78bSCy Schubert     if (t == NULL)
74*7f2fe78bSCy Schubert         return;
75*7f2fe78bSCy Schubert     for (i = 0; i < K5_KEY_MAX; i++) {
76*7f2fe78bSCy Schubert         if (destructors_set[i] && destructors[i] && t->values[i]) {
77*7f2fe78bSCy Schubert             void *v = t->values[i];
78*7f2fe78bSCy Schubert             t->values[i] = 0;
79*7f2fe78bSCy Schubert             (*destructors[i])(v);
80*7f2fe78bSCy Schubert         }
81*7f2fe78bSCy Schubert     }
82*7f2fe78bSCy Schubert }
83*7f2fe78bSCy Schubert 
84*7f2fe78bSCy Schubert /* Stub function not used on Windows. */
krb5int_pthread_loaded(void)85*7f2fe78bSCy Schubert int krb5int_pthread_loaded (void)
86*7f2fe78bSCy Schubert {
87*7f2fe78bSCy Schubert     return 0;
88*7f2fe78bSCy Schubert }
89*7f2fe78bSCy Schubert #else /* POSIX threads */
90*7f2fe78bSCy Schubert 
91*7f2fe78bSCy Schubert /* Must support register/delete/register sequence, e.g., if krb5 is
92*7f2fe78bSCy Schubert    loaded so this support code stays in the process, and gssapi is
93*7f2fe78bSCy Schubert    loaded, unloaded, and loaded again.  */
94*7f2fe78bSCy Schubert 
95*7f2fe78bSCy Schubert static k5_mutex_t key_lock = K5_MUTEX_PARTIAL_INITIALIZER;
96*7f2fe78bSCy Schubert static void (*destructors[K5_KEY_MAX])(void *);
97*7f2fe78bSCy Schubert static unsigned char destructors_set[K5_KEY_MAX];
98*7f2fe78bSCy Schubert 
99*7f2fe78bSCy Schubert /* This is not safe yet!
100*7f2fe78bSCy Schubert 
101*7f2fe78bSCy Schubert    Thread termination concurrent with key deletion can cause two
102*7f2fe78bSCy Schubert    threads to interfere.  It's a bit tricky, since one of the threads
103*7f2fe78bSCy Schubert    will want to remove this structure from the list being walked by
104*7f2fe78bSCy Schubert    the other.
105*7f2fe78bSCy Schubert 
106*7f2fe78bSCy Schubert    Other cases, like looking up data while the library owning the key
107*7f2fe78bSCy Schubert    is in the process of being unloaded, we don't worry about.  */
108*7f2fe78bSCy Schubert 
109*7f2fe78bSCy Schubert struct tsd_block {
110*7f2fe78bSCy Schubert     struct tsd_block *next;
111*7f2fe78bSCy Schubert     void *values[K5_KEY_MAX];
112*7f2fe78bSCy Schubert };
113*7f2fe78bSCy Schubert 
114*7f2fe78bSCy Schubert #ifdef HAVE_PRAGMA_WEAK_REF
115*7f2fe78bSCy Schubert # pragma weak pthread_once
116*7f2fe78bSCy Schubert # pragma weak pthread_mutex_lock
117*7f2fe78bSCy Schubert # pragma weak pthread_mutex_unlock
118*7f2fe78bSCy Schubert # pragma weak pthread_mutex_destroy
119*7f2fe78bSCy Schubert # pragma weak pthread_mutex_init
120*7f2fe78bSCy Schubert # pragma weak pthread_self
121*7f2fe78bSCy Schubert # pragma weak pthread_equal
122*7f2fe78bSCy Schubert # pragma weak pthread_getspecific
123*7f2fe78bSCy Schubert # pragma weak pthread_setspecific
124*7f2fe78bSCy Schubert # pragma weak pthread_key_create
125*7f2fe78bSCy Schubert # pragma weak pthread_key_delete
126*7f2fe78bSCy Schubert # pragma weak pthread_create
127*7f2fe78bSCy Schubert # pragma weak pthread_join
128*7f2fe78bSCy Schubert # define K5_PTHREADS_LOADED     (krb5int_pthread_loaded())
129*7f2fe78bSCy Schubert static volatile int flag_pthread_loaded = -1;
loaded_test_aux(void)130*7f2fe78bSCy Schubert static void loaded_test_aux(void)
131*7f2fe78bSCy Schubert {
132*7f2fe78bSCy Schubert     if (flag_pthread_loaded == -1)
133*7f2fe78bSCy Schubert         flag_pthread_loaded = 1;
134*7f2fe78bSCy Schubert     else
135*7f2fe78bSCy Schubert         /* Could we have been called twice?  */
136*7f2fe78bSCy Schubert         flag_pthread_loaded = 0;
137*7f2fe78bSCy Schubert }
138*7f2fe78bSCy Schubert static pthread_once_t loaded_test_once = PTHREAD_ONCE_INIT;
krb5int_pthread_loaded(void)139*7f2fe78bSCy Schubert int krb5int_pthread_loaded (void)
140*7f2fe78bSCy Schubert {
141*7f2fe78bSCy Schubert     int x = flag_pthread_loaded;
142*7f2fe78bSCy Schubert     if (x != -1)
143*7f2fe78bSCy Schubert         return x;
144*7f2fe78bSCy Schubert     if (&pthread_getspecific == 0
145*7f2fe78bSCy Schubert         || &pthread_setspecific == 0
146*7f2fe78bSCy Schubert         || &pthread_key_create == 0
147*7f2fe78bSCy Schubert         || &pthread_key_delete == 0
148*7f2fe78bSCy Schubert         || &pthread_once == 0
149*7f2fe78bSCy Schubert         || &pthread_mutex_lock == 0
150*7f2fe78bSCy Schubert         || &pthread_mutex_unlock == 0
151*7f2fe78bSCy Schubert         || &pthread_mutex_destroy == 0
152*7f2fe78bSCy Schubert         || &pthread_mutex_init == 0
153*7f2fe78bSCy Schubert         || &pthread_self == 0
154*7f2fe78bSCy Schubert         || &pthread_equal == 0
155*7f2fe78bSCy Schubert         /* Any program that's really multithreaded will have to be
156*7f2fe78bSCy Schubert            able to create threads.  */
157*7f2fe78bSCy Schubert         || &pthread_create == 0
158*7f2fe78bSCy Schubert         || &pthread_join == 0
159*7f2fe78bSCy Schubert         /* Okay, all the interesting functions -- or stubs for them --
160*7f2fe78bSCy Schubert            seem to be present.  If we call pthread_once, does it
161*7f2fe78bSCy Schubert            actually seem to cause the indicated function to get called
162*7f2fe78bSCy Schubert            exactly one time?  */
163*7f2fe78bSCy Schubert         || pthread_once(&loaded_test_once, loaded_test_aux) != 0
164*7f2fe78bSCy Schubert         || pthread_once(&loaded_test_once, loaded_test_aux) != 0
165*7f2fe78bSCy Schubert         /* This catches cases where pthread_once does nothing, and
166*7f2fe78bSCy Schubert            never causes the function to get called.  That's a pretty
167*7f2fe78bSCy Schubert            clear violation of the POSIX spec, but hey, it happens.  */
168*7f2fe78bSCy Schubert         || flag_pthread_loaded < 0) {
169*7f2fe78bSCy Schubert         flag_pthread_loaded = 0;
170*7f2fe78bSCy Schubert         return 0;
171*7f2fe78bSCy Schubert     }
172*7f2fe78bSCy Schubert     /* If we wanted to be super-paranoid, we could try testing whether
173*7f2fe78bSCy Schubert        pthread_get/setspecific work, too.  I don't know -- so far --
174*7f2fe78bSCy Schubert        of any system with non-functional stubs for those.  */
175*7f2fe78bSCy Schubert     return flag_pthread_loaded;
176*7f2fe78bSCy Schubert }
177*7f2fe78bSCy Schubert 
178*7f2fe78bSCy Schubert static struct tsd_block tsd_if_single;
179*7f2fe78bSCy Schubert # define GET_NO_PTHREAD_TSD()   (&tsd_if_single)
180*7f2fe78bSCy Schubert #else
181*7f2fe78bSCy Schubert # define K5_PTHREADS_LOADED     (1)
krb5int_pthread_loaded(void)182*7f2fe78bSCy Schubert int krb5int_pthread_loaded (void)
183*7f2fe78bSCy Schubert {
184*7f2fe78bSCy Schubert     return 1;
185*7f2fe78bSCy Schubert }
186*7f2fe78bSCy Schubert 
187*7f2fe78bSCy Schubert # define GET_NO_PTHREAD_TSD()   (abort(),(struct tsd_block *)0)
188*7f2fe78bSCy Schubert #endif
189*7f2fe78bSCy Schubert 
190*7f2fe78bSCy Schubert static pthread_key_t key;
191*7f2fe78bSCy Schubert static void thread_termination(void *);
192*7f2fe78bSCy Schubert 
thread_termination(void * tptr)193*7f2fe78bSCy Schubert static void thread_termination (void *tptr)
194*7f2fe78bSCy Schubert {
195*7f2fe78bSCy Schubert     int i, pass, none_found;
196*7f2fe78bSCy Schubert     struct tsd_block *t = tptr;
197*7f2fe78bSCy Schubert 
198*7f2fe78bSCy Schubert     k5_mutex_lock(&key_lock);
199*7f2fe78bSCy Schubert 
200*7f2fe78bSCy Schubert     /*
201*7f2fe78bSCy Schubert      * Make multiple passes in case, for example, a libkrb5 cleanup
202*7f2fe78bSCy Schubert      * function wants to print out an error message, which causes
203*7f2fe78bSCy Schubert      * com_err to allocate a thread-specific buffer, after we just
204*7f2fe78bSCy Schubert      * freed up the old one.
205*7f2fe78bSCy Schubert      *
206*7f2fe78bSCy Schubert      * Shouldn't actually happen, if we're careful, but check just in
207*7f2fe78bSCy Schubert      * case.
208*7f2fe78bSCy Schubert      */
209*7f2fe78bSCy Schubert 
210*7f2fe78bSCy Schubert     pass = 0;
211*7f2fe78bSCy Schubert     none_found = 0;
212*7f2fe78bSCy Schubert     while (pass < 4 && !none_found) {
213*7f2fe78bSCy Schubert         none_found = 1;
214*7f2fe78bSCy Schubert         for (i = 0; i < K5_KEY_MAX; i++) {
215*7f2fe78bSCy Schubert             if (destructors_set[i] && destructors[i] && t->values[i]) {
216*7f2fe78bSCy Schubert                 void *v = t->values[i];
217*7f2fe78bSCy Schubert                 t->values[i] = 0;
218*7f2fe78bSCy Schubert                 (*destructors[i])(v);
219*7f2fe78bSCy Schubert                 none_found = 0;
220*7f2fe78bSCy Schubert             }
221*7f2fe78bSCy Schubert         }
222*7f2fe78bSCy Schubert     }
223*7f2fe78bSCy Schubert     free (t);
224*7f2fe78bSCy Schubert     k5_mutex_unlock(&key_lock);
225*7f2fe78bSCy Schubert 
226*7f2fe78bSCy Schubert     /* remove thread from global linked list */
227*7f2fe78bSCy Schubert }
228*7f2fe78bSCy Schubert 
229*7f2fe78bSCy Schubert #endif /* no threads vs Win32 vs POSIX */
230*7f2fe78bSCy Schubert 
k5_getspecific(k5_key_t keynum)231*7f2fe78bSCy Schubert void *k5_getspecific (k5_key_t keynum)
232*7f2fe78bSCy Schubert {
233*7f2fe78bSCy Schubert     struct tsd_block *t;
234*7f2fe78bSCy Schubert     int err;
235*7f2fe78bSCy Schubert 
236*7f2fe78bSCy Schubert     err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
237*7f2fe78bSCy Schubert     if (err)
238*7f2fe78bSCy Schubert         return NULL;
239*7f2fe78bSCy Schubert 
240*7f2fe78bSCy Schubert     assert(destructors_set[keynum] == 1);
241*7f2fe78bSCy Schubert 
242*7f2fe78bSCy Schubert #ifndef ENABLE_THREADS
243*7f2fe78bSCy Schubert 
244*7f2fe78bSCy Schubert     t = &tsd_no_threads;
245*7f2fe78bSCy Schubert 
246*7f2fe78bSCy Schubert #elif defined(_WIN32)
247*7f2fe78bSCy Schubert 
248*7f2fe78bSCy Schubert     t = TlsGetValue(tls_idx);
249*7f2fe78bSCy Schubert 
250*7f2fe78bSCy Schubert #else /* POSIX */
251*7f2fe78bSCy Schubert 
252*7f2fe78bSCy Schubert     if (K5_PTHREADS_LOADED)
253*7f2fe78bSCy Schubert         t = pthread_getspecific(key);
254*7f2fe78bSCy Schubert     else
255*7f2fe78bSCy Schubert         t = GET_NO_PTHREAD_TSD();
256*7f2fe78bSCy Schubert 
257*7f2fe78bSCy Schubert #endif
258*7f2fe78bSCy Schubert 
259*7f2fe78bSCy Schubert     if (t == NULL)
260*7f2fe78bSCy Schubert         return NULL;
261*7f2fe78bSCy Schubert     return t->values[keynum];
262*7f2fe78bSCy Schubert }
263*7f2fe78bSCy Schubert 
k5_setspecific(k5_key_t keynum,void * value)264*7f2fe78bSCy Schubert int k5_setspecific (k5_key_t keynum, void *value)
265*7f2fe78bSCy Schubert {
266*7f2fe78bSCy Schubert     struct tsd_block *t;
267*7f2fe78bSCy Schubert     int err;
268*7f2fe78bSCy Schubert 
269*7f2fe78bSCy Schubert     err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
270*7f2fe78bSCy Schubert     if (err)
271*7f2fe78bSCy Schubert         return err;
272*7f2fe78bSCy Schubert 
273*7f2fe78bSCy Schubert     assert(destructors_set[keynum] == 1);
274*7f2fe78bSCy Schubert 
275*7f2fe78bSCy Schubert #ifndef ENABLE_THREADS
276*7f2fe78bSCy Schubert 
277*7f2fe78bSCy Schubert     t = &tsd_no_threads;
278*7f2fe78bSCy Schubert 
279*7f2fe78bSCy Schubert #elif defined(_WIN32)
280*7f2fe78bSCy Schubert 
281*7f2fe78bSCy Schubert     t = TlsGetValue(tls_idx);
282*7f2fe78bSCy Schubert     if (t == NULL) {
283*7f2fe78bSCy Schubert         int i;
284*7f2fe78bSCy Schubert         t = malloc(sizeof(*t));
285*7f2fe78bSCy Schubert         if (t == NULL)
286*7f2fe78bSCy Schubert             return ENOMEM;
287*7f2fe78bSCy Schubert         for (i = 0; i < K5_KEY_MAX; i++)
288*7f2fe78bSCy Schubert             t->values[i] = 0;
289*7f2fe78bSCy Schubert         /* add to global linked list */
290*7f2fe78bSCy Schubert         /*      t->next = 0; */
291*7f2fe78bSCy Schubert         err = TlsSetValue(tls_idx, t);
292*7f2fe78bSCy Schubert         if (!err) {
293*7f2fe78bSCy Schubert             free(t);
294*7f2fe78bSCy Schubert             return GetLastError();
295*7f2fe78bSCy Schubert         }
296*7f2fe78bSCy Schubert     }
297*7f2fe78bSCy Schubert 
298*7f2fe78bSCy Schubert #else /* POSIX */
299*7f2fe78bSCy Schubert 
300*7f2fe78bSCy Schubert     if (K5_PTHREADS_LOADED) {
301*7f2fe78bSCy Schubert         t = pthread_getspecific(key);
302*7f2fe78bSCy Schubert         if (t == NULL) {
303*7f2fe78bSCy Schubert             int i;
304*7f2fe78bSCy Schubert             t = malloc(sizeof(*t));
305*7f2fe78bSCy Schubert             if (t == NULL)
306*7f2fe78bSCy Schubert                 return ENOMEM;
307*7f2fe78bSCy Schubert             for (i = 0; i < K5_KEY_MAX; i++)
308*7f2fe78bSCy Schubert                 t->values[i] = 0;
309*7f2fe78bSCy Schubert             /* add to global linked list */
310*7f2fe78bSCy Schubert             t->next = 0;
311*7f2fe78bSCy Schubert             err = pthread_setspecific(key, t);
312*7f2fe78bSCy Schubert             if (err) {
313*7f2fe78bSCy Schubert                 free(t);
314*7f2fe78bSCy Schubert                 return err;
315*7f2fe78bSCy Schubert             }
316*7f2fe78bSCy Schubert         }
317*7f2fe78bSCy Schubert     } else {
318*7f2fe78bSCy Schubert         t = GET_NO_PTHREAD_TSD();
319*7f2fe78bSCy Schubert     }
320*7f2fe78bSCy Schubert 
321*7f2fe78bSCy Schubert #endif
322*7f2fe78bSCy Schubert 
323*7f2fe78bSCy Schubert     t->values[keynum] = value;
324*7f2fe78bSCy Schubert     return 0;
325*7f2fe78bSCy Schubert }
326*7f2fe78bSCy Schubert 
k5_key_register(k5_key_t keynum,void (* destructor)(void *))327*7f2fe78bSCy Schubert int k5_key_register (k5_key_t keynum, void (*destructor)(void *))
328*7f2fe78bSCy Schubert {
329*7f2fe78bSCy Schubert     int err;
330*7f2fe78bSCy Schubert 
331*7f2fe78bSCy Schubert     err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
332*7f2fe78bSCy Schubert     if (err)
333*7f2fe78bSCy Schubert         return err;
334*7f2fe78bSCy Schubert 
335*7f2fe78bSCy Schubert #ifndef ENABLE_THREADS
336*7f2fe78bSCy Schubert 
337*7f2fe78bSCy Schubert     assert(destructors_set[keynum] == 0);
338*7f2fe78bSCy Schubert     destructors[keynum] = destructor;
339*7f2fe78bSCy Schubert     destructors_set[keynum] = 1;
340*7f2fe78bSCy Schubert 
341*7f2fe78bSCy Schubert #elif defined(_WIN32)
342*7f2fe78bSCy Schubert 
343*7f2fe78bSCy Schubert     /* XXX: This can raise EXCEPTION_POSSIBLE_DEADLOCK.  */
344*7f2fe78bSCy Schubert     EnterCriticalSection(&key_lock);
345*7f2fe78bSCy Schubert     assert(destructors_set[keynum] == 0);
346*7f2fe78bSCy Schubert     destructors_set[keynum] = 1;
347*7f2fe78bSCy Schubert     destructors[keynum] = destructor;
348*7f2fe78bSCy Schubert     LeaveCriticalSection(&key_lock);
349*7f2fe78bSCy Schubert 
350*7f2fe78bSCy Schubert #else /* POSIX */
351*7f2fe78bSCy Schubert 
352*7f2fe78bSCy Schubert     k5_mutex_lock(&key_lock);
353*7f2fe78bSCy Schubert     assert(destructors_set[keynum] == 0);
354*7f2fe78bSCy Schubert     destructors_set[keynum] = 1;
355*7f2fe78bSCy Schubert     destructors[keynum] = destructor;
356*7f2fe78bSCy Schubert     k5_mutex_unlock(&key_lock);
357*7f2fe78bSCy Schubert 
358*7f2fe78bSCy Schubert #endif
359*7f2fe78bSCy Schubert     return 0;
360*7f2fe78bSCy Schubert }
361*7f2fe78bSCy Schubert 
k5_key_delete(k5_key_t keynum)362*7f2fe78bSCy Schubert int k5_key_delete (k5_key_t keynum)
363*7f2fe78bSCy Schubert {
364*7f2fe78bSCy Schubert #ifndef ENABLE_THREADS
365*7f2fe78bSCy Schubert 
366*7f2fe78bSCy Schubert     assert(destructors_set[keynum] == 1);
367*7f2fe78bSCy Schubert     if (destructors[keynum] && tsd_no_threads.values[keynum])
368*7f2fe78bSCy Schubert         (*destructors[keynum])(tsd_no_threads.values[keynum]);
369*7f2fe78bSCy Schubert     destructors[keynum] = 0;
370*7f2fe78bSCy Schubert     tsd_no_threads.values[keynum] = 0;
371*7f2fe78bSCy Schubert     destructors_set[keynum] = 0;
372*7f2fe78bSCy Schubert 
373*7f2fe78bSCy Schubert #elif defined(_WIN32)
374*7f2fe78bSCy Schubert 
375*7f2fe78bSCy Schubert     /* XXX: This can raise EXCEPTION_POSSIBLE_DEADLOCK.  */
376*7f2fe78bSCy Schubert     EnterCriticalSection(&key_lock);
377*7f2fe78bSCy Schubert     /* XXX Memory leak here!
378*7f2fe78bSCy Schubert        Need to destroy the associated data for all threads.
379*7f2fe78bSCy Schubert        But watch for race conditions in case threads are going away too.  */
380*7f2fe78bSCy Schubert     assert(destructors_set[keynum] == 1);
381*7f2fe78bSCy Schubert     destructors_set[keynum] = 0;
382*7f2fe78bSCy Schubert     destructors[keynum] = 0;
383*7f2fe78bSCy Schubert     LeaveCriticalSection(&key_lock);
384*7f2fe78bSCy Schubert 
385*7f2fe78bSCy Schubert #else /* POSIX */
386*7f2fe78bSCy Schubert 
387*7f2fe78bSCy Schubert     /* XXX RESOURCE LEAK: Need to destroy the allocated objects first!  */
388*7f2fe78bSCy Schubert     k5_mutex_lock(&key_lock);
389*7f2fe78bSCy Schubert     assert(destructors_set[keynum] == 1);
390*7f2fe78bSCy Schubert     destructors_set[keynum] = 0;
391*7f2fe78bSCy Schubert     destructors[keynum] = NULL;
392*7f2fe78bSCy Schubert     k5_mutex_unlock(&key_lock);
393*7f2fe78bSCy Schubert 
394*7f2fe78bSCy Schubert #endif
395*7f2fe78bSCy Schubert 
396*7f2fe78bSCy Schubert     return 0;
397*7f2fe78bSCy Schubert }
398*7f2fe78bSCy Schubert 
krb5int_call_thread_support_init(void)399*7f2fe78bSCy Schubert int krb5int_call_thread_support_init (void)
400*7f2fe78bSCy Schubert {
401*7f2fe78bSCy Schubert     return CALL_INIT_FUNCTION(krb5int_thread_support_init);
402*7f2fe78bSCy Schubert }
403*7f2fe78bSCy Schubert 
404*7f2fe78bSCy Schubert #include "cache-addrinfo.h"
405*7f2fe78bSCy Schubert 
krb5int_thread_support_init(void)406*7f2fe78bSCy Schubert int krb5int_thread_support_init (void)
407*7f2fe78bSCy Schubert {
408*7f2fe78bSCy Schubert     int err;
409*7f2fe78bSCy Schubert 
410*7f2fe78bSCy Schubert #ifdef SHOW_INITFINI_FUNCS
411*7f2fe78bSCy Schubert     printf("krb5int_thread_support_init\n");
412*7f2fe78bSCy Schubert #endif
413*7f2fe78bSCy Schubert 
414*7f2fe78bSCy Schubert #ifndef ENABLE_THREADS
415*7f2fe78bSCy Schubert 
416*7f2fe78bSCy Schubert     /* Nothing to do for TLS initialization.  */
417*7f2fe78bSCy Schubert 
418*7f2fe78bSCy Schubert #elif defined(_WIN32)
419*7f2fe78bSCy Schubert 
420*7f2fe78bSCy Schubert     tls_idx = TlsAlloc();
421*7f2fe78bSCy Schubert     /* XXX This can raise an exception if memory is low!  */
422*7f2fe78bSCy Schubert     InitializeCriticalSection(&key_lock);
423*7f2fe78bSCy Schubert 
424*7f2fe78bSCy Schubert #else /* POSIX */
425*7f2fe78bSCy Schubert 
426*7f2fe78bSCy Schubert     err = k5_mutex_finish_init(&key_lock);
427*7f2fe78bSCy Schubert     if (err)
428*7f2fe78bSCy Schubert         return err;
429*7f2fe78bSCy Schubert     if (K5_PTHREADS_LOADED) {
430*7f2fe78bSCy Schubert         err = pthread_key_create(&key, thread_termination);
431*7f2fe78bSCy Schubert         if (err)
432*7f2fe78bSCy Schubert             return err;
433*7f2fe78bSCy Schubert     }
434*7f2fe78bSCy Schubert 
435*7f2fe78bSCy Schubert #endif
436*7f2fe78bSCy Schubert 
437*7f2fe78bSCy Schubert     err = krb5int_init_fac();
438*7f2fe78bSCy Schubert     if (err)
439*7f2fe78bSCy Schubert         return err;
440*7f2fe78bSCy Schubert 
441*7f2fe78bSCy Schubert     err = krb5int_err_init();
442*7f2fe78bSCy Schubert     if (err)
443*7f2fe78bSCy Schubert         return err;
444*7f2fe78bSCy Schubert 
445*7f2fe78bSCy Schubert     return 0;
446*7f2fe78bSCy Schubert }
447*7f2fe78bSCy Schubert 
krb5int_thread_support_fini(void)448*7f2fe78bSCy Schubert void krb5int_thread_support_fini (void)
449*7f2fe78bSCy Schubert {
450*7f2fe78bSCy Schubert     if (! INITIALIZER_RAN (krb5int_thread_support_init))
451*7f2fe78bSCy Schubert         return;
452*7f2fe78bSCy Schubert 
453*7f2fe78bSCy Schubert #ifdef SHOW_INITFINI_FUNCS
454*7f2fe78bSCy Schubert     printf("krb5int_thread_support_fini\n");
455*7f2fe78bSCy Schubert #endif
456*7f2fe78bSCy Schubert 
457*7f2fe78bSCy Schubert #ifndef ENABLE_THREADS
458*7f2fe78bSCy Schubert 
459*7f2fe78bSCy Schubert     /* Do nothing.  */
460*7f2fe78bSCy Schubert 
461*7f2fe78bSCy Schubert #elif defined(_WIN32)
462*7f2fe78bSCy Schubert 
463*7f2fe78bSCy Schubert     /* ... free stuff ... */
464*7f2fe78bSCy Schubert     TlsFree(tls_idx);
465*7f2fe78bSCy Schubert     DeleteCriticalSection(&key_lock);
466*7f2fe78bSCy Schubert 
467*7f2fe78bSCy Schubert #else /* POSIX */
468*7f2fe78bSCy Schubert 
469*7f2fe78bSCy Schubert     if (! INITIALIZER_RAN(krb5int_thread_support_init))
470*7f2fe78bSCy Schubert         return;
471*7f2fe78bSCy Schubert     if (K5_PTHREADS_LOADED)
472*7f2fe78bSCy Schubert         pthread_key_delete(key);
473*7f2fe78bSCy Schubert     /* ... delete stuff ... */
474*7f2fe78bSCy Schubert     k5_mutex_destroy(&key_lock);
475*7f2fe78bSCy Schubert 
476*7f2fe78bSCy Schubert #endif
477*7f2fe78bSCy Schubert 
478*7f2fe78bSCy Schubert     krb5int_fini_fac();
479*7f2fe78bSCy Schubert }
480*7f2fe78bSCy Schubert 
481*7f2fe78bSCy Schubert /* Mutex allocation functions, for use in plugins that may not know
482*7f2fe78bSCy Schubert    what options a given set of libraries was compiled with.  */
483*7f2fe78bSCy Schubert int KRB5_CALLCONV
krb5int_mutex_alloc(k5_mutex_t ** m)484*7f2fe78bSCy Schubert krb5int_mutex_alloc (k5_mutex_t **m)
485*7f2fe78bSCy Schubert {
486*7f2fe78bSCy Schubert     k5_mutex_t *ptr;
487*7f2fe78bSCy Schubert     int err;
488*7f2fe78bSCy Schubert 
489*7f2fe78bSCy Schubert     ptr = malloc (sizeof (k5_mutex_t));
490*7f2fe78bSCy Schubert     if (ptr == NULL)
491*7f2fe78bSCy Schubert         return ENOMEM;
492*7f2fe78bSCy Schubert     err = k5_mutex_init (ptr);
493*7f2fe78bSCy Schubert     if (err) {
494*7f2fe78bSCy Schubert         free (ptr);
495*7f2fe78bSCy Schubert         return err;
496*7f2fe78bSCy Schubert     }
497*7f2fe78bSCy Schubert     *m = ptr;
498*7f2fe78bSCy Schubert     return 0;
499*7f2fe78bSCy Schubert }
500*7f2fe78bSCy Schubert 
501*7f2fe78bSCy Schubert void KRB5_CALLCONV
krb5int_mutex_free(k5_mutex_t * m)502*7f2fe78bSCy Schubert krb5int_mutex_free (k5_mutex_t *m)
503*7f2fe78bSCy Schubert {
504*7f2fe78bSCy Schubert     (void) k5_mutex_destroy (m);
505*7f2fe78bSCy Schubert     free (m);
506*7f2fe78bSCy Schubert }
507*7f2fe78bSCy Schubert 
508*7f2fe78bSCy Schubert /* Callable versions of the various macros.  */
509*7f2fe78bSCy Schubert void KRB5_CALLCONV
krb5int_mutex_lock(k5_mutex_t * m)510*7f2fe78bSCy Schubert krb5int_mutex_lock (k5_mutex_t *m)
511*7f2fe78bSCy Schubert {
512*7f2fe78bSCy Schubert     k5_mutex_lock (m);
513*7f2fe78bSCy Schubert }
514*7f2fe78bSCy Schubert void KRB5_CALLCONV
krb5int_mutex_unlock(k5_mutex_t * m)515*7f2fe78bSCy Schubert krb5int_mutex_unlock (k5_mutex_t *m)
516*7f2fe78bSCy Schubert {
517*7f2fe78bSCy Schubert     k5_mutex_unlock (m);
518*7f2fe78bSCy Schubert }
519*7f2fe78bSCy Schubert 
520*7f2fe78bSCy Schubert #ifdef USE_CONDITIONAL_PTHREADS
521*7f2fe78bSCy Schubert 
522*7f2fe78bSCy Schubert int
k5_os_mutex_init(k5_os_mutex * m)523*7f2fe78bSCy Schubert k5_os_mutex_init(k5_os_mutex *m)
524*7f2fe78bSCy Schubert {
525*7f2fe78bSCy Schubert     if (krb5int_pthread_loaded())
526*7f2fe78bSCy Schubert         return pthread_mutex_init(m, 0);
527*7f2fe78bSCy Schubert     else
528*7f2fe78bSCy Schubert         return 0;
529*7f2fe78bSCy Schubert }
530*7f2fe78bSCy Schubert 
531*7f2fe78bSCy Schubert int
k5_os_mutex_destroy(k5_os_mutex * m)532*7f2fe78bSCy Schubert k5_os_mutex_destroy(k5_os_mutex *m)
533*7f2fe78bSCy Schubert {
534*7f2fe78bSCy Schubert     if (krb5int_pthread_loaded())
535*7f2fe78bSCy Schubert         return pthread_mutex_destroy(m);
536*7f2fe78bSCy Schubert     else
537*7f2fe78bSCy Schubert         return 0;
538*7f2fe78bSCy Schubert }
539*7f2fe78bSCy Schubert 
540*7f2fe78bSCy Schubert int
k5_os_mutex_lock(k5_os_mutex * m)541*7f2fe78bSCy Schubert k5_os_mutex_lock(k5_os_mutex *m)
542*7f2fe78bSCy Schubert {
543*7f2fe78bSCy Schubert     if (krb5int_pthread_loaded())
544*7f2fe78bSCy Schubert         return pthread_mutex_lock(m);
545*7f2fe78bSCy Schubert     else
546*7f2fe78bSCy Schubert         return 0;
547*7f2fe78bSCy Schubert }
548*7f2fe78bSCy Schubert 
549*7f2fe78bSCy Schubert int
k5_os_mutex_unlock(k5_os_mutex * m)550*7f2fe78bSCy Schubert k5_os_mutex_unlock(k5_os_mutex *m)
551*7f2fe78bSCy Schubert {
552*7f2fe78bSCy Schubert     if (krb5int_pthread_loaded())
553*7f2fe78bSCy Schubert         return pthread_mutex_unlock(m);
554*7f2fe78bSCy Schubert     else
555*7f2fe78bSCy Schubert         return 0;
556*7f2fe78bSCy Schubert }
557*7f2fe78bSCy Schubert 
558*7f2fe78bSCy Schubert int
k5_once(k5_once_t * once,void (* fn)(void))559*7f2fe78bSCy Schubert k5_once(k5_once_t *once, void (*fn)(void))
560*7f2fe78bSCy Schubert {
561*7f2fe78bSCy Schubert     if (krb5int_pthread_loaded())
562*7f2fe78bSCy Schubert         return pthread_once(&once->o, fn);
563*7f2fe78bSCy Schubert     else
564*7f2fe78bSCy Schubert         return k5_os_nothread_once(&once->n, fn);
565*7f2fe78bSCy Schubert }
566*7f2fe78bSCy Schubert 
567*7f2fe78bSCy Schubert #else /* USE_CONDITIONAL_PTHREADS */
568*7f2fe78bSCy Schubert 
569*7f2fe78bSCy Schubert #undef k5_os_mutex_init
570*7f2fe78bSCy Schubert #undef k5_os_mutex_destroy
571*7f2fe78bSCy Schubert #undef k5_os_mutex_lock
572*7f2fe78bSCy Schubert #undef k5_os_mutex_unlock
573*7f2fe78bSCy Schubert #undef k5_once
574*7f2fe78bSCy Schubert 
575*7f2fe78bSCy Schubert int k5_os_mutex_init(k5_os_mutex *m);
576*7f2fe78bSCy Schubert int k5_os_mutex_destroy(k5_os_mutex *m);
577*7f2fe78bSCy Schubert int k5_os_mutex_lock(k5_os_mutex *m);
578*7f2fe78bSCy Schubert int k5_os_mutex_unlock(k5_os_mutex *m);
579*7f2fe78bSCy Schubert int k5_once(k5_once_t *once, void (*fn)(void));
580*7f2fe78bSCy Schubert 
581*7f2fe78bSCy Schubert /* Stub functions */
582*7f2fe78bSCy Schubert int
k5_os_mutex_init(k5_os_mutex * m)583*7f2fe78bSCy Schubert k5_os_mutex_init(k5_os_mutex *m)
584*7f2fe78bSCy Schubert {
585*7f2fe78bSCy Schubert     return 0;
586*7f2fe78bSCy Schubert }
587*7f2fe78bSCy Schubert int
k5_os_mutex_destroy(k5_os_mutex * m)588*7f2fe78bSCy Schubert k5_os_mutex_destroy(k5_os_mutex *m)
589*7f2fe78bSCy Schubert {
590*7f2fe78bSCy Schubert     return 0;
591*7f2fe78bSCy Schubert }
592*7f2fe78bSCy Schubert int
k5_os_mutex_lock(k5_os_mutex * m)593*7f2fe78bSCy Schubert k5_os_mutex_lock(k5_os_mutex *m)
594*7f2fe78bSCy Schubert {
595*7f2fe78bSCy Schubert     return 0;
596*7f2fe78bSCy Schubert }
597*7f2fe78bSCy Schubert int
k5_os_mutex_unlock(k5_os_mutex * m)598*7f2fe78bSCy Schubert k5_os_mutex_unlock(k5_os_mutex *m)
599*7f2fe78bSCy Schubert {
600*7f2fe78bSCy Schubert     return 0;
601*7f2fe78bSCy Schubert }
602*7f2fe78bSCy Schubert int
k5_once(k5_once_t * once,void (* fn)(void))603*7f2fe78bSCy Schubert k5_once(k5_once_t *once, void (*fn)(void))
604*7f2fe78bSCy Schubert {
605*7f2fe78bSCy Schubert     return 0;
606*7f2fe78bSCy Schubert }
607*7f2fe78bSCy Schubert 
608*7f2fe78bSCy Schubert #endif /* not USE_CONDITIONAL_PTHREADS */
609