Convert DEBUG_REFERRALS to TRACE_* framework
[krb5.git] / src / include / k5-thread.h
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* include/k5-thread.h - Preliminary portable thread support */
3 /*
4  * Copyright 2004,2005,2006,2007,2008 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26
27 #ifndef K5_THREAD_H
28 #define K5_THREAD_H
29
30 #include "autoconf.h"
31 #ifndef KRB5_CALLCONV
32 # define KRB5_CALLCONV
33 #endif
34 #ifndef KRB5_CALLCONV_C
35 # define KRB5_CALLCONV_C
36 #endif
37
38 \f/* Interface (tentative):
39
40      Mutex support:
41
42      // Between these two, we should be able to do pure compile-time
43      // and pure run-time initialization.
44      //   POSIX:   partial initializer is PTHREAD_MUTEX_INITIALIZER,
45      //            finish does nothing
46      //   Windows: partial initializer is an invalid handle,
47      //            finish does the real initialization work
48      k5_mutex_t foo_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
49      int k5_mutex_finish_init(k5_mutex_t *);
50      // for dynamic allocation
51      int k5_mutex_init(k5_mutex_t *);
52      // Must work for both kinds of alloc, even if it means adding flags.
53      int k5_mutex_destroy(k5_mutex_t *);
54
55      // As before.
56      int k5_mutex_lock(k5_mutex_t *);
57      int k5_mutex_unlock(k5_mutex_t *);
58
59      In each library, one new function to finish the static mutex init,
60      and any other library-wide initialization that might be desired.
61      On POSIX, this function would be called via the second support
62      function (see below).  On Windows, it would be called at library
63      load time.  These functions, or functions they calls, should be the
64      only places that k5_mutex_finish_init gets called.
65
66      A second function or macro called at various possible "first" entry
67      points which either calls pthread_once on the first function
68      (POSIX), or checks some flag set by the first function (Windows),
69      and possibly returns an error.  (In the non-threaded case, a simple
70      flag can be used to avoid multiple invocations, and the mutexes
71      don't need run-time initialization anyways.)
72
73      A third function for library termination calls mutex_destroy on
74      each mutex for the library.  This function would be called
75      automatically at library unload time.  If it turns out to be needed
76      at exit time for libraries that don't get unloaded, perhaps we
77      should also use atexit().  Any static mutexes should be cleaned up
78      with k5_mutex_destroy here.
79
80      How does that second support function invoke the first support
81      function only once?  Through something modelled on pthread_once
82      that I haven't written up yet.  Probably:
83
84      k5_once_t foo_once = K5_ONCE_INIT;
85      k5_once(k5_once_t *, void (*)(void));
86
87      For POSIX: Map onto pthread_once facility.
88      For non-threaded case: A simple flag.
89      For Windows: Not needed; library init code takes care of it.
90
91      XXX: A general k5_once mechanism isn't possible for Windows,
92      without faking it through named mutexes or mutexes initialized at
93      startup.  I was only using it in one place outside these headers,
94      so I'm dropping the general scheme.  Eventually the existing uses
95      in k5-thread.h and k5-platform.h will be converted to pthread_once
96      or static variables.
97
98
99      Thread-specific data:
100
101      // TSD keys are limited in number in gssapi/krb5/com_err; enumerate
102      // them all.  This allows support code init to allocate the
103      // necessary storage for pointers all at once, and avoids any
104      // possible error in key creation.
105      enum { ... } k5_key_t;
106      // Register destructor function.  Called in library init code.
107      int k5_key_register(k5_key_t, void (*destructor)(void *));
108      // Returns NULL or data.
109      void *k5_getspecific(k5_key_t);
110      // Returns error if key out of bounds, or the pointer table can't
111      // be allocated.  A call to k5_key_register must have happened first.
112      // This may trigger the calling of pthread_setspecific on POSIX.
113      int k5_setspecific(k5_key_t, void *);
114      // Called in library termination code.
115      // Trashes data in all threads, calling the registered destructor
116      // (but calling it from the current thread).
117      int k5_key_delete(k5_key_t);
118
119      For the non-threaded version, the support code will have a static
120      array indexed by k5_key_t values, and get/setspecific simply access
121      the array elements.
122
123      The TSD destructor table is global state, protected by a mutex if
124      threads are enabled.
125
126
127      Any actual external symbols will use the krb5int_ prefix.  The k5_
128      names will be simple macros or inline functions to rename the
129      external symbols, or slightly more complex ones to expand the
130      implementation inline (e.g., map to POSIX versions and/or debug
131      code using __FILE__ and the like).
132
133
134      More to be added, perhaps.  */
135
136 #include <assert.h>
137 \f
138
139 /* The mutex structure we use, k5_mutex_t, is defined to some
140    OS-specific bits.  The use of multiple layers of typedefs are an
141    artifact resulting from debugging code we once used, implemented as
142    wrappers around the OS mutex scheme.
143
144    The OS specific bits, in k5_os_mutex, break down into three primary
145    implementations, POSIX threads, Windows threads, and no thread
146    support.  However, the POSIX thread version is further subdivided:
147    In one case, we can determine at run time whether the thread
148    library is linked into the application, and use it only if it is
149    present; in the other case, we cannot, and the thread library must
150    be linked in always, but can be used unconditionally.  In the
151    former case, the k5_os_mutex structure needs to hold both the POSIX
152    and the non-threaded versions.
153
154    The various k5_os_mutex_* operations are the OS-specific versions,
155    applied to the OS-specific data, and k5_mutex_* uses k5_os_mutex_*
156    to do the OS-specific parts of the work.  */
157
158 /* Define the OS mutex bit.  */
159
160 typedef char k5_os_nothread_mutex;
161 # define K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER       0
162 /* Empty inline functions avoid the "statement with no effect"
163    warnings, and do better type-checking than functions that don't use
164    their arguments.  */
165 static inline int k5_os_nothread_mutex_finish_init(k5_os_nothread_mutex *m) {
166     return 0;
167 }
168 static inline int k5_os_nothread_mutex_init(k5_os_nothread_mutex *m) {
169     return 0;
170 }
171 static inline int k5_os_nothread_mutex_destroy(k5_os_nothread_mutex *m) {
172     return 0;
173 }
174 static inline int k5_os_nothread_mutex_lock(k5_os_nothread_mutex *m) {
175     return 0;
176 }
177 static inline int k5_os_nothread_mutex_unlock(k5_os_nothread_mutex *m) {
178     return 0;
179 }
180
181 /* Values:
182    2 - function has not been run
183    3 - function has been run
184    4 - function is being run -- deadlock detected */
185 typedef unsigned char k5_os_nothread_once_t;
186 # define K5_OS_NOTHREAD_ONCE_INIT       2
187 # define k5_os_nothread_once(O,F)                               \
188     (*(O) == 3 ? 0                                              \
189      : *(O) == 2 ? (*(O) = 4, (F)(), *(O) = 3, 0)               \
190      : (assert(*(O) != 4), assert(*(O) == 2 || *(O) == 3), 0))
191
192
193
194 #ifndef ENABLE_THREADS
195
196 typedef k5_os_nothread_mutex k5_os_mutex;
197 # define K5_OS_MUTEX_PARTIAL_INITIALIZER        \
198     K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER
199 # define k5_os_mutex_finish_init        k5_os_nothread_mutex_finish_init
200 # define k5_os_mutex_init               k5_os_nothread_mutex_init
201 # define k5_os_mutex_destroy            k5_os_nothread_mutex_destroy
202 # define k5_os_mutex_lock               k5_os_nothread_mutex_lock
203 # define k5_os_mutex_unlock             k5_os_nothread_mutex_unlock
204
205 # define k5_once_t                      k5_os_nothread_once_t
206 # define K5_ONCE_INIT                   K5_OS_NOTHREAD_ONCE_INIT
207 # define k5_once                        k5_os_nothread_once
208
209 #elif HAVE_PTHREAD
210
211 # include <pthread.h>
212
213 /* Weak reference support, etc.
214
215    Linux: Stub mutex routines exist, but pthread_once does not.
216
217    Solaris <10: In libc there's a pthread_once that doesn't seem to do
218    anything.  Bleah.  But pthread_mutexattr_setrobust_np is defined
219    only in libpthread.  However, some version of GNU libc (Red Hat's
220    Fedora Core 5, reportedly) seems to have that function, but no
221    declaration, so we'd have to declare it in order to test for its
222    address.  We now have tests to see if pthread_once actually works,
223    so stick with that for now.
224
225    Solaris 10: The real thread support now lives in libc, and
226    libpthread is just a filter object.  So we might as well use the
227    real functions unconditionally.  Since we haven't got a test for
228    this property yet, we use NO_WEAK_PTHREADS defined in aclocal.m4
229    depending on the OS type.
230
231    IRIX 6.5 stub pthread support in libc is really annoying.  The
232    pthread_mutex_lock function returns ENOSYS for a program not linked
233    against -lpthread.  No link-time failure, no weak symbols, etc.
234    The C library doesn't provide pthread_once; we can use weak
235    reference support for that.
236
237    If weak references are not available, then for now, we assume that
238    the pthread support routines will always be available -- either the
239    real thing, or functional stubs that merely prohibit creating
240    threads.
241
242    If we find a platform with non-functional stubs and no weak
243    references, we may have to resort to some hack like dlsym on the
244    symbol tables of the current process.  */
245 extern int krb5int_pthread_loaded(void)
246 #ifdef __GNUC__
247 /* We should always get the same answer for the life of the process.  */
248     __attribute__((const))
249 #endif
250     ;
251 #if defined(HAVE_PRAGMA_WEAK_REF) && !defined(NO_WEAK_PTHREADS)
252 # pragma weak pthread_once
253 # pragma weak pthread_mutex_lock
254 # pragma weak pthread_mutex_unlock
255 # pragma weak pthread_mutex_destroy
256 # pragma weak pthread_mutex_init
257 # pragma weak pthread_self
258 # pragma weak pthread_equal
259 # define K5_PTHREADS_LOADED     (krb5int_pthread_loaded())
260 # define USE_PTHREAD_LOCK_ONLY_IF_LOADED
261
262 /* Can't rely on useful stubs -- see above regarding Solaris.  */
263 typedef struct {
264     pthread_once_t o;
265     k5_os_nothread_once_t n;
266 } k5_once_t;
267 # define K5_ONCE_INIT   { PTHREAD_ONCE_INIT, K5_OS_NOTHREAD_ONCE_INIT }
268 # define k5_once(O,F)   (K5_PTHREADS_LOADED                     \
269                          ? pthread_once(&(O)->o,F)              \
270                          : k5_os_nothread_once(&(O)->n,F))
271
272 #else
273
274 /* no pragma weak support */
275 # define K5_PTHREADS_LOADED     (1)
276
277 typedef pthread_once_t k5_once_t;
278 # define K5_ONCE_INIT   PTHREAD_ONCE_INIT
279 # define k5_once        pthread_once
280
281 #endif
282
283 #if defined(__mips) && defined(__sgi) && (defined(_SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__))
284 # ifndef HAVE_PRAGMA_WEAK_REF
285 #  if defined(__GNUC__) && __GNUC__ < 3
286 #   error "Please update to a newer gcc with weak symbol support, or switch to native cc, reconfigure and recompile."
287 #  else
288 #   error "Weak reference support is required"
289 #  endif
290 # endif
291 #endif
292
293 typedef pthread_mutex_t k5_os_mutex;
294 # define K5_OS_MUTEX_PARTIAL_INITIALIZER        \
295     PTHREAD_MUTEX_INITIALIZER
296
297 #ifdef USE_PTHREAD_LOCK_ONLY_IF_LOADED
298
299 # define k5_os_mutex_finish_init(M)             (0)
300 # define k5_os_mutex_init(M)                                    \
301     (K5_PTHREADS_LOADED ? pthread_mutex_init((M), 0) : 0)
302 # define k5_os_mutex_destroy(M)                                 \
303     (K5_PTHREADS_LOADED ? pthread_mutex_destroy((M)) : 0)
304 # define k5_os_mutex_lock(M)                            \
305     (K5_PTHREADS_LOADED ? pthread_mutex_lock(M) : 0)
306 # define k5_os_mutex_unlock(M)                          \
307     (K5_PTHREADS_LOADED ? pthread_mutex_unlock(M) : 0)
308
309 #else
310
311 static inline int k5_os_mutex_finish_init(k5_os_mutex *m) { return 0; }
312 # define k5_os_mutex_init(M)            pthread_mutex_init((M), 0)
313 # define k5_os_mutex_destroy(M)         pthread_mutex_destroy((M))
314 # define k5_os_mutex_lock(M)            pthread_mutex_lock(M)
315 # define k5_os_mutex_unlock(M)          pthread_mutex_unlock(M)
316
317 #endif /* is pthreads always available? */
318
319 #elif defined _WIN32
320
321 typedef struct {
322     HANDLE h;
323     int is_locked;
324 } k5_os_mutex;
325
326 # define K5_OS_MUTEX_PARTIAL_INITIALIZER { INVALID_HANDLE_VALUE, 0 }
327
328 # define k5_os_mutex_finish_init(M)                                     \
329     (assert((M)->h == INVALID_HANDLE_VALUE),                            \
330      ((M)->h = CreateMutex(NULL, FALSE, NULL)) ? 0 : GetLastError())
331 # define k5_os_mutex_init(M)                                            \
332     ((M)->is_locked = 0,                                                \
333      ((M)->h = CreateMutex(NULL, FALSE, NULL)) ? 0 : GetLastError())
334 # define k5_os_mutex_destroy(M)                                 \
335     (CloseHandle((M)->h) ? ((M)->h = 0, 0) : GetLastError())
336
337 static inline int k5_os_mutex_lock(k5_os_mutex *m)
338 {
339     DWORD res;
340     res = WaitForSingleObject(m->h, INFINITE);
341     if (res == WAIT_FAILED)
342         return GetLastError();
343     /* Eventually these should be turned into some reasonable error
344        code.  */
345     assert(res != WAIT_TIMEOUT);
346     assert(res != WAIT_ABANDONED);
347     assert(res == WAIT_OBJECT_0);
348     /* Avoid locking twice.  */
349     assert(m->is_locked == 0);
350     m->is_locked = 1;
351     return 0;
352 }
353
354 # define k5_os_mutex_unlock(M)                  \
355     (assert((M)->is_locked == 1),               \
356      (M)->is_locked = 0,                        \
357      ReleaseMutex((M)->h) ? 0 : GetLastError())
358
359 #else
360
361 # error "Thread support enabled, but thread system unknown"
362
363 #endif
364
365
366 \f
367
368 typedef k5_os_mutex k5_mutex_t;
369 #define K5_MUTEX_PARTIAL_INITIALIZER    K5_OS_MUTEX_PARTIAL_INITIALIZER
370 static inline int k5_mutex_init(k5_mutex_t *m)
371 {
372     return k5_os_mutex_init(m);
373 }
374 static inline int k5_mutex_finish_init(k5_mutex_t *m)
375 {
376     return k5_os_mutex_finish_init(m);
377 }
378 #define k5_mutex_destroy(M)                     \
379     (k5_os_mutex_destroy(M))
380
381 #if __GNUC__ >= 4
382 static int k5_mutex_lock(k5_mutex_t *)
383     __attribute__((warn_unused_result));
384 #endif
385 static inline int k5_mutex_lock(k5_mutex_t *m)
386 {
387     return k5_os_mutex_lock(m);
388 }
389
390 #define k5_mutex_unlock(M)                      \
391     (k5_os_mutex_unlock(M))
392
393 #define k5_mutex_assert_locked(M)       ((void)(M))
394 #define k5_mutex_assert_unlocked(M)     ((void)(M))
395 #define k5_assert_locked        k5_mutex_assert_locked
396 #define k5_assert_unlocked      k5_mutex_assert_unlocked
397
398 \f
399 /* Thread-specific data; implemented in a support file, because we'll
400    need to keep track of some global data for cleanup purposes.
401
402    Note that the callback function type is such that the C library
403    routine free() is a valid callback.  */
404 typedef enum {
405     K5_KEY_COM_ERR,
406     K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME,
407     K5_KEY_GSS_KRB5_CCACHE_NAME,
408     K5_KEY_GSS_KRB5_ERROR_MESSAGE,
409     K5_KEY_KIM_ERROR_MESSAGE,
410 #if defined(__MACH__) && defined(__APPLE__)
411     K5_KEY_IPC_CONNECTION_INFO,
412     K5_KEY_COM_ERR_REENTER,
413 #endif
414     K5_KEY_MAX
415 } k5_key_t;
416 /* rename shorthand symbols for export */
417 #define k5_key_register krb5int_key_register
418 #define k5_getspecific  krb5int_getspecific
419 #define k5_setspecific  krb5int_setspecific
420 #define k5_key_delete   krb5int_key_delete
421 extern int k5_key_register(k5_key_t, void (*)(void *));
422 extern void *k5_getspecific(k5_key_t);
423 extern int k5_setspecific(k5_key_t, void *);
424 extern int k5_key_delete(k5_key_t);
425
426 extern int  KRB5_CALLCONV krb5int_mutex_alloc  (k5_mutex_t **);
427 extern void KRB5_CALLCONV krb5int_mutex_free   (k5_mutex_t *);
428 extern int  KRB5_CALLCONV krb5int_mutex_lock   (k5_mutex_t *)
429 #if __GNUC__ >= 4
430     __attribute__((warn_unused_result))
431 #endif
432     ;
433 extern int  KRB5_CALLCONV krb5int_mutex_unlock (k5_mutex_t *);
434
435 /* In time, many of the definitions above should move into the support
436    library, and this file should be greatly simplified.  For type
437    definitions, that'll take some work, since other data structures
438    incorporate mutexes directly, and our mutex type is dependent on
439    configuration options and system attributes.  For most functions,
440    though, it should be relatively easy.
441
442    For now, plugins should use the exported functions, and not the
443    above macros, and use krb5int_mutex_alloc for allocations.  */
444 #if defined(PLUGIN) || (defined(CONFIG_SMALL) && !defined(THREAD_SUPPORT_IMPL))
445 #undef k5_mutex_lock
446 #define k5_mutex_lock krb5int_mutex_lock
447 #undef k5_mutex_unlock
448 #define k5_mutex_unlock krb5int_mutex_unlock
449 #endif
450
451 #endif /* multiple inclusion? */