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