xref: /onnv-gate/usr/src/uts/common/gssapi/mechs/krb5/include/k5-thread.h (revision 13132:9615cdbf7b70)
1781Sgtb /*
2*13132SGlenn.Barry@oracle.com  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3781Sgtb  */
4781Sgtb 
5781Sgtb /*
6781Sgtb  * include/k5-thread.h
7781Sgtb  *
84960Swillf  * Copyright 2004,2005,2006 by the Massachusetts Institute of Technology.
9781Sgtb  * All Rights Reserved.
10781Sgtb  *
11781Sgtb  * Export of this software from the United States of America may
12781Sgtb  *   require a specific license from the United States Government.
13781Sgtb  *   It is the responsibility of any person or organization contemplating
14781Sgtb  *   export to obtain such a license before exporting.
15781Sgtb  *
16781Sgtb  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
17781Sgtb  * distribute this software and its documentation for any purpose and
18781Sgtb  * without fee is hereby granted, provided that the above copyright
19781Sgtb  * notice appear in all copies and that both that copyright notice and
20781Sgtb  * this permission notice appear in supporting documentation, and that
21781Sgtb  * the name of M.I.T. not be used in advertising or publicity pertaining
22781Sgtb  * to distribution of the software without specific, written prior
23781Sgtb  * permission.  Furthermore if you modify this software you must label
24781Sgtb  * your software as modified software and not distribute it in such a
25781Sgtb  * fashion that it might be confused with the original M.I.T. software.
26781Sgtb  * M.I.T. makes no representations about the suitability of
27781Sgtb  * this software for any purpose.  It is provided "as is" without express
28781Sgtb  * or implied warranty.
29781Sgtb  *
30781Sgtb  *
31781Sgtb  * Preliminary thread support.
32781Sgtb  */
33781Sgtb 
34781Sgtb #ifndef K5_THREAD_H
35781Sgtb #define K5_THREAD_H
36781Sgtb 
375053Sgtb #ifdef _KERNEL
385053Sgtb 
395053Sgtb #include <sys/ksynch.h>
405053Sgtb 
415053Sgtb typedef kmutex_t k5_mutex_t;
425053Sgtb 
435053Sgtb #define K5_MUTEX_PARTIAL_INITIALIZER {0}
445053Sgtb 
455053Sgtb /* ARGSUSED */
k5_mutex_assert_locked(k5_mutex_t * m)465053Sgtb static void k5_mutex_assert_locked(k5_mutex_t *m) { }
475053Sgtb 
485053Sgtb static int
k5_mutex_lock(k5_mutex_t * m)495053Sgtb k5_mutex_lock(k5_mutex_t *m)
505053Sgtb {
515053Sgtb   mutex_enter(m);
525053Sgtb   return (0);
535053Sgtb }
545053Sgtb 
555053Sgtb static int
k5_mutex_unlock(k5_mutex_t * m)565053Sgtb k5_mutex_unlock(k5_mutex_t *m)
575053Sgtb {
585053Sgtb   mutex_exit(m);
595053Sgtb   return(0);
605053Sgtb }
615053Sgtb 
625053Sgtb 
635053Sgtb #else /* _KERNEL */
645053Sgtb 
65781Sgtb #include "autoconf.h"
664960Swillf #ifndef KRB5_CALLCONV
674960Swillf # define KRB5_CALLCONV
684960Swillf #endif
694960Swillf #ifndef KRB5_CALLCONV_C
704960Swillf # define KRB5_CALLCONV_C
714960Swillf #endif
724960Swillf 
73781Sgtb /* Interface (tentative):
74781Sgtb 
75781Sgtb    Mutex support:
76781Sgtb 
77781Sgtb    // Between these two, we should be able to do pure compile-time
78781Sgtb    // and pure run-time initialization.
79781Sgtb    //   POSIX:   partial initializer is PTHREAD_MUTEX_INITIALIZER,
80781Sgtb    //            finish does nothing
81781Sgtb    //   Windows: partial initializer is an invalid handle,
82781Sgtb    //            finish does the real initialization work
83781Sgtb    //   debug:   partial initializer sets one magic value,
84781Sgtb    //            finish verifies and sets a new magic value for
85781Sgtb    //              lock/unlock to check
86781Sgtb    k5_mutex_t foo_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
87781Sgtb    int k5_mutex_finish_init(k5_mutex_t *);
88781Sgtb    // for dynamic allocation
89781Sgtb    int k5_mutex_init(k5_mutex_t *);
90781Sgtb    // Must work for both kinds of alloc, even if it means adding flags.
91781Sgtb    int k5_mutex_destroy(k5_mutex_t *);
92781Sgtb 
93781Sgtb    // As before.
94781Sgtb    int k5_mutex_lock(k5_mutex_t *);
95781Sgtb    int k5_mutex_unlock(k5_mutex_t *);
96781Sgtb 
97781Sgtb    In each library, one new function to finish the static mutex init,
98781Sgtb    and any other library-wide initialization that might be desired.
99781Sgtb    On POSIX, this function would be called via the second support
100781Sgtb    function (see below).  On Windows, it would be called at library
101781Sgtb    load time.  These functions, or functions they calls, should be the
102781Sgtb    only places that k5_mutex_finish_init gets called.
103781Sgtb 
104781Sgtb    A second function or macro called at various possible "first" entry
105781Sgtb    points which either calls pthread_once on the first function
106781Sgtb    (POSIX), or checks some flag set by the first function (Windows,
107781Sgtb    debug support), and possibly returns an error.  (In the
108781Sgtb    non-threaded case, a simple flag can be used to avoid multiple
109781Sgtb    invocations, and the mutexes don't need run-time initialization
110781Sgtb    anyways.)
111781Sgtb 
112781Sgtb    A third function for library termination calls mutex_destroy on
113781Sgtb    each mutex for the library.  This function would be called
114781Sgtb    automatically at library unload time.  If it turns out to be needed
115781Sgtb    at exit time for libraries that don't get unloaded, perhaps we
116781Sgtb    should also use atexit().  Any static mutexes should be cleaned up
117781Sgtb    with k5_mutex_destroy here.
118781Sgtb 
119781Sgtb    How does that second support function invoke the first support
120781Sgtb    function only once?  Through something modelled on pthread_once
121781Sgtb    that I haven't written up yet.  Probably:
122781Sgtb 
123781Sgtb    k5_once_t foo_once = K5_ONCE_INIT;
124781Sgtb    k5_once(k5_once_t *, void (*)(void));
125781Sgtb 
126781Sgtb    For POSIX: Map onto pthread_once facility.
127781Sgtb    For non-threaded case: A simple flag.
128781Sgtb    For Windows: Not needed; library init code takes care of it.
129781Sgtb 
130781Sgtb    XXX: A general k5_once mechanism isn't possible for Windows,
131781Sgtb    without faking it through named mutexes or mutexes initialized at
132781Sgtb    startup.  I was only using it in one place outside these headers,
133781Sgtb    so I'm dropping the general scheme.  Eventually the existing uses
134781Sgtb    in k5-thread.h and k5-platform.h will be converted to pthread_once
135781Sgtb    or static variables.
136781Sgtb 
137781Sgtb 
138781Sgtb    Thread-specific data:
139781Sgtb 
140781Sgtb    // TSD keys are limited in number in gssapi/krb5/com_err; enumerate
141781Sgtb    // them all.  This allows support code init to allocate the
142781Sgtb    // necessary storage for pointers all at once, and avoids any
143781Sgtb    // possible error in key creation.
144781Sgtb    enum { ... } k5_key_t;
145781Sgtb    // Register destructor function.  Called in library init code.
146781Sgtb    int k5_key_register(k5_key_t, void (*destructor)(void *));
147781Sgtb    // Returns NULL or data.
148781Sgtb    void *k5_getspecific(k5_key_t);
149781Sgtb    // Returns error if key out of bounds, or the pointer table can't
150781Sgtb    // be allocated.  A call to k5_key_register must have happened first.
151781Sgtb    // This may trigger the calling of pthread_setspecific on POSIX.
152781Sgtb    int k5_setspecific(k5_key_t, void *);
153781Sgtb    // Called in library termination code.
154781Sgtb    // Trashes data in all threads, calling the registered destructor
155781Sgtb    // (but calling it from the current thread).
156781Sgtb    int k5_key_delete(k5_key_t);
157781Sgtb 
158781Sgtb    For the non-threaded version, the support code will have a static
159781Sgtb    array indexed by k5_key_t values, and get/setspecific simply access
160781Sgtb    the array elements.
161781Sgtb 
162781Sgtb    The TSD destructor table is global state, protected by a mutex if
163781Sgtb    threads are enabled.
164781Sgtb 
165781Sgtb    Debug support: Not much.  Might check if k5_key_register has been
166781Sgtb    called and abort if not.
167781Sgtb 
168781Sgtb 
169781Sgtb    Any actual external symbols will use the krb5int_ prefix.  The k5_
170781Sgtb    names will be simple macros or inline functions to rename the
171781Sgtb    external symbols, or slightly more complex ones to expand the
172781Sgtb    implementation inline (e.g., map to POSIX versions and/or debug
173781Sgtb    code using __FILE__ and the like).
174781Sgtb 
175781Sgtb 
176781Sgtb    More to be added, perhaps.  */
177781Sgtb 
178781Sgtb #undef DEBUG_THREADS /* SUNW14resync XXX */
179781Sgtb #undef DEBUG_THREADS_LOC /* SUNW14resync XXX */
180781Sgtb #undef DEBUG_THREADS_SLOW /* debugging stuff that'll slow things down? */
181781Sgtb #undef DEBUG_THREADS_STATS
182781Sgtb 
183781Sgtb #ifndef _KERNEL
184781Sgtb #include <assert.h>
185781Sgtb #include <stdarg.h>
186781Sgtb #define ASSERT assert
187781Sgtb #endif
188781Sgtb 
189781Sgtb /* For tracking locations, of (e.g.) last lock or unlock of mutex.  */
190781Sgtb #ifdef DEBUG_THREADS_LOC
191781Sgtb typedef struct {
192781Sgtb     const char *filename;
1934960Swillf     int lineno;
194781Sgtb } k5_debug_loc;
195781Sgtb #define K5_DEBUG_LOC_INIT	{ __FILE__, __LINE__ }
196781Sgtb #if __GNUC__ >= 2
197781Sgtb #define K5_DEBUG_LOC		(__extension__ (k5_debug_loc)K5_DEBUG_LOC_INIT)
198781Sgtb #else
k5_debug_make_loc(const char * file,int line)1997934SMark.Phalan@Sun.COM static inline k5_debug_loc k5_debug_make_loc(const char *file, int line)
200781Sgtb {
201781Sgtb     k5_debug_loc l;
202781Sgtb     l.filename = file;
203781Sgtb     l.lineno = line;
204781Sgtb     return l;
205781Sgtb }
206781Sgtb #define K5_DEBUG_LOC		(k5_debug_make_loc(__FILE__,__LINE__))
207781Sgtb #endif
208781Sgtb #else /* ! DEBUG_THREADS_LOC */
209781Sgtb typedef char k5_debug_loc;
210781Sgtb #define K5_DEBUG_LOC_INIT	0
211781Sgtb #define K5_DEBUG_LOC		0
212781Sgtb #endif
213781Sgtb 
214781Sgtb #define k5_debug_update_loc(L)	((L) = K5_DEBUG_LOC)
215781Sgtb 
216781Sgtb 
217781Sgtb 
218781Sgtb /* Statistics gathering:
219781Sgtb 
220781Sgtb    Currently incomplete, don't try enabling it.
221781Sgtb 
222781Sgtb    Eventually: Report number of times locked, total and standard
223781Sgtb    deviation of the time the lock was held, total and std dev time
224781Sgtb    spent waiting for the lock.  "Report" will probably mean "write a
225781Sgtb    line to a file if a magic environment variable is set."  */
226781Sgtb 
227781Sgtb #ifdef DEBUG_THREADS_STATS
228781Sgtb 
229781Sgtb #if HAVE_TIME_H && (!defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME))
230781Sgtb # include <time.h>
231781Sgtb #endif
232781Sgtb #if HAVE_SYS_TIME_H
233781Sgtb # include <sys/time.h>
234781Sgtb #endif
235781Sgtb #ifdef HAVE_STDINT_H
236781Sgtb # include <stdint.h>
237781Sgtb #endif
2384960Swillf /* for memset */
2394960Swillf #include <string.h>
2404960Swillf /* for uint64_t */
241781Sgtb #include <inttypes.h>
2424960Swillf typedef uint64_t k5_debug_timediff_t; /* or long double */
243781Sgtb typedef struct timeval k5_debug_time_t;
244781Sgtb static inline k5_debug_timediff_t
timediff(k5_debug_time_t t2,k5_debug_time_t t1)245781Sgtb timediff(k5_debug_time_t t2, k5_debug_time_t t1)
246781Sgtb {
247781Sgtb     return (t2.tv_sec - t1.tv_sec) * 1000000 + (t2.tv_usec - t1.tv_usec);
248781Sgtb }
get_current_time(void)2497934SMark.Phalan@Sun.COM static inline k5_debug_time_t get_current_time(void)
2507934SMark.Phalan@Sun.COM {
2517934SMark.Phalan@Sun.COM     struct timeval tv;
2527934SMark.Phalan@Sun.COM     if (gettimeofday(&tv,0) < 0) { tv.tv_sec = tv.tv_usec = 0; }
2537934SMark.Phalan@Sun.COM     return tv;
2547934SMark.Phalan@Sun.COM }
255781Sgtb struct k5_timediff_stats {
256781Sgtb     k5_debug_timediff_t valmin, valmax, valsum, valsqsum;
257781Sgtb };
258781Sgtb typedef struct {
259781Sgtb     int count;
260781Sgtb     k5_debug_time_t time_acquired, time_created;
261781Sgtb     struct k5_timediff_stats lockwait, lockheld;
262781Sgtb } k5_debug_mutex_stats;
2637934SMark.Phalan@Sun.COM #define k5_mutex_init_stats(S)					\
2647934SMark.Phalan@Sun.COM 	(memset((S), 0, sizeof(k5_debug_mutex_stats)),	\
2657934SMark.Phalan@Sun.COM 	 (S)->time_created = get_current_time(),		\
2667934SMark.Phalan@Sun.COM 	 0)
267781Sgtb #define k5_mutex_finish_init_stats(S) 	(0)
268781Sgtb #define K5_MUTEX_STATS_INIT	{ 0, {0}, {0}, {0}, {0} }
2697934SMark.Phalan@Sun.COM typedef k5_debug_time_t k5_mutex_stats_tmp;
2707934SMark.Phalan@Sun.COM #define k5_mutex_stats_start()	get_current_time()
2717934SMark.Phalan@Sun.COM void KRB5_CALLCONV krb5int_mutex_lock_update_stats(k5_debug_mutex_stats *m,
2727934SMark.Phalan@Sun.COM 						   k5_mutex_stats_tmp start);
2737934SMark.Phalan@Sun.COM void KRB5_CALLCONV krb5int_mutex_unlock_update_stats(k5_debug_mutex_stats *m);
2747934SMark.Phalan@Sun.COM #define k5_mutex_lock_update_stats	krb5int_mutex_lock_update_stats
2757934SMark.Phalan@Sun.COM #define k5_mutex_unlock_update_stats	krb5int_mutex_unlock_update_stats
2767934SMark.Phalan@Sun.COM void KRB5_CALLCONV krb5int_mutex_report_stats(/* k5_mutex_t *m */);
277781Sgtb 
278781Sgtb #else
279781Sgtb 
280781Sgtb typedef char k5_debug_mutex_stats;
281781Sgtb #define k5_mutex_init_stats(S)		(*(S) = 's', 0)
282781Sgtb #define k5_mutex_finish_init_stats(S)	(0)
283781Sgtb #define K5_MUTEX_STATS_INIT		's'
2847934SMark.Phalan@Sun.COM typedef int k5_mutex_stats_tmp;
2857934SMark.Phalan@Sun.COM #define k5_mutex_stats_start()		(0)
2867934SMark.Phalan@Sun.COM #ifdef __GNUC__
2877934SMark.Phalan@Sun.COM static void
k5_mutex_lock_update_stats(k5_debug_mutex_stats * m,k5_mutex_stats_tmp t)2887934SMark.Phalan@Sun.COM k5_mutex_lock_update_stats(k5_debug_mutex_stats *m, k5_mutex_stats_tmp t)
2897934SMark.Phalan@Sun.COM {
2907934SMark.Phalan@Sun.COM }
2917934SMark.Phalan@Sun.COM #else
2927934SMark.Phalan@Sun.COM # define k5_mutex_lock_update_stats(M,S)	(S)
2937934SMark.Phalan@Sun.COM #endif
2947934SMark.Phalan@Sun.COM #define k5_mutex_unlock_update_stats(M)	(*(M) = 's')
2957934SMark.Phalan@Sun.COM 
2967934SMark.Phalan@Sun.COM /* If statistics tracking isn't enabled, these functions don't actually
2977934SMark.Phalan@Sun.COM    do anything.  Declare anyways so we can do type checking etc.  */
2987934SMark.Phalan@Sun.COM void KRB5_CALLCONV krb5int_mutex_lock_update_stats(k5_debug_mutex_stats *m,
2997934SMark.Phalan@Sun.COM 						   k5_mutex_stats_tmp start);
3007934SMark.Phalan@Sun.COM void KRB5_CALLCONV krb5int_mutex_unlock_update_stats(k5_debug_mutex_stats *m);
3017934SMark.Phalan@Sun.COM void KRB5_CALLCONV krb5int_mutex_report_stats(/* k5_mutex_t *m */);
3027934SMark.Phalan@Sun.COM 
3037934SMark.Phalan@Sun.COM #define krb5int_mutex_report_stats(M)	((M)->stats = 'd')
304781Sgtb 
305781Sgtb #endif
306781Sgtb 
307781Sgtb 
308781Sgtb 
309781Sgtb /* Define the OS mutex bit.  */
310781Sgtb 
311781Sgtb /* First, if we're not actually doing multiple threads, do we
312781Sgtb    want the debug support or not?  */
313781Sgtb 
314781Sgtb #ifdef DEBUG_THREADS
315781Sgtb 
316781Sgtb enum k5_mutex_init_states {
317781Sgtb     K5_MUTEX_DEBUG_PARTLY_INITIALIZED = 0x12,
318781Sgtb     K5_MUTEX_DEBUG_INITIALIZED,
319781Sgtb     K5_MUTEX_DEBUG_DESTROYED
320781Sgtb };
321781Sgtb enum k5_mutex_flag_states {
322781Sgtb     K5_MUTEX_DEBUG_UNLOCKED = 0x23,
323781Sgtb     K5_MUTEX_DEBUG_LOCKED
324781Sgtb };
325781Sgtb 
326781Sgtb typedef struct {
327781Sgtb     enum k5_mutex_init_states initialized;
328781Sgtb     enum k5_mutex_flag_states locked;
329781Sgtb } k5_os_nothread_mutex;
330781Sgtb 
331781Sgtb # define K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER \
332781Sgtb 	{ K5_MUTEX_DEBUG_PARTLY_INITIALIZED, K5_MUTEX_DEBUG_UNLOCKED }
333781Sgtb 
334781Sgtb # define k5_os_nothread_mutex_finish_init(M)				\
335781Sgtb 	(ASSERT((M)->initialized != K5_MUTEX_DEBUG_INITIALIZED),	\
336781Sgtb 	 ASSERT((M)->initialized == K5_MUTEX_DEBUG_PARTLY_INITIALIZED),	\
337781Sgtb 	 ASSERT((M)->locked == K5_MUTEX_DEBUG_UNLOCKED),		\
338781Sgtb 	 (M)->initialized = K5_MUTEX_DEBUG_INITIALIZED, 0)
339781Sgtb # define k5_os_nothread_mutex_init(M)			\
340781Sgtb 	((M)->initialized = K5_MUTEX_DEBUG_INITIALIZED,	\
341781Sgtb 	 (M)->locked = K5_MUTEX_DEBUG_UNLOCKED, 0)
342781Sgtb # define k5_os_nothread_mutex_destroy(M)				\
343781Sgtb 	(ASSERT((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED),	\
344781Sgtb 	 (M)->initialized = K5_MUTEX_DEBUG_DESTROYED, 0)
345781Sgtb 
346781Sgtb # define k5_os_nothread_mutex_lock(M)			\
347781Sgtb 	(k5_os_nothread_mutex_assert_unlocked(M),	\
348781Sgtb 	 (M)->locked = K5_MUTEX_DEBUG_LOCKED, 0)
349781Sgtb # define k5_os_nothread_mutex_unlock(M)			\
350781Sgtb 	(k5_os_nothread_mutex_assert_locked(M),		\
351781Sgtb 	 (M)->locked = K5_MUTEX_DEBUG_UNLOCKED, 0)
352781Sgtb 
353781Sgtb # define k5_os_nothread_mutex_assert_locked(M)				\
354781Sgtb 	(ASSERT((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED),	\
355781Sgtb 	 ASSERT((M)->locked != K5_MUTEX_DEBUG_UNLOCKED),		\
356781Sgtb 	 ASSERT((M)->locked == K5_MUTEX_DEBUG_LOCKED))
357781Sgtb # define k5_os_nothread_mutex_assert_unlocked(M)			\
358781Sgtb 	(ASSERT((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED),	\
359781Sgtb 	 ASSERT((M)->locked != K5_MUTEX_DEBUG_LOCKED),			\
360781Sgtb 	 ASSERT((M)->locked == K5_MUTEX_DEBUG_UNLOCKED))
361781Sgtb 
362781Sgtb #else /* threads disabled and not debugging */
363781Sgtb typedef char k5_os_nothread_mutex;
364781Sgtb # define K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER	0
365781Sgtb /* Empty inline functions avoid the "statement with no effect"
366781Sgtb    warnings, and do better type-checking than functions that don't use
367781Sgtb    their arguments.  */
368781Sgtb /* SUNW 1.4resync, remove "inline" to avoid warning */
369781Sgtb /* ARGSUSED */
370781Sgtb /* LINTED */
k5_os_nothread_mutex_finish_init(k5_os_nothread_mutex * m)371781Sgtb static int k5_os_nothread_mutex_finish_init(k5_os_nothread_mutex *m) {
372781Sgtb     return 0;
373781Sgtb }
374781Sgtb /* ARGSUSED */
375781Sgtb /* LINTED */
k5_os_nothread_mutex_init(k5_os_nothread_mutex * m)376781Sgtb static int k5_os_nothread_mutex_init(k5_os_nothread_mutex *m) {
377781Sgtb     return 0;
378781Sgtb }
379781Sgtb /* ARGSUSED */
380781Sgtb /* LINTED */
k5_os_nothread_mutex_destroy(k5_os_nothread_mutex * m)381781Sgtb static int k5_os_nothread_mutex_destroy(k5_os_nothread_mutex *m) {
382781Sgtb     return 0;
383781Sgtb }
384781Sgtb /* ARGSUSED */
385781Sgtb /* LINTED */
k5_os_nothread_mutex_lock(k5_os_nothread_mutex * m)386781Sgtb static int k5_os_nothread_mutex_lock(k5_os_nothread_mutex *m) {
387781Sgtb     return 0;
388781Sgtb }
389781Sgtb /* ARGSUSED */
390781Sgtb /* LINTED */
k5_os_nothread_mutex_unlock(k5_os_nothread_mutex * m)391781Sgtb static int k5_os_nothread_mutex_unlock(k5_os_nothread_mutex *m) {
392781Sgtb     return 0;
393781Sgtb }
394781Sgtb # define k5_os_nothread_mutex_assert_locked(M)		((void)0)
395781Sgtb # define k5_os_nothread_mutex_assert_unlocked(M)	((void)0)
396781Sgtb 
397781Sgtb #endif
398781Sgtb 
399781Sgtb /* Values:
400781Sgtb    2 - function has not been run
401781Sgtb    3 - function has been run
402781Sgtb    4 - function is being run -- deadlock detected */
403781Sgtb typedef unsigned char k5_os_nothread_once_t;
404781Sgtb # define K5_OS_NOTHREAD_ONCE_INIT	2
405781Sgtb # define k5_os_nothread_once(O,F)					\
406781Sgtb 	(*(O) == 3 ? 0							\
407781Sgtb 	 : *(O) == 2 ? (*(O) = 4, (F)(), *(O) = 3, 0)			\
408781Sgtb 	 : (ASSERT(*(O) != 4), ASSERT(*(O) == 2 || *(O) == 3), 0))
409781Sgtb 
410781Sgtb 
411781Sgtb 
412781Sgtb #ifndef ENABLE_THREADS
413781Sgtb typedef k5_os_nothread_mutex k5_os_mutex;
414781Sgtb # define K5_OS_MUTEX_PARTIAL_INITIALIZER	\
415781Sgtb 		K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER
416781Sgtb # define k5_os_mutex_finish_init	k5_os_nothread_mutex_finish_init
417781Sgtb # define k5_os_mutex_init		k5_os_nothread_mutex_init
418781Sgtb # define k5_os_mutex_destroy		k5_os_nothread_mutex_destroy
419781Sgtb # define k5_os_mutex_lock		k5_os_nothread_mutex_lock
420781Sgtb # define k5_os_mutex_unlock		k5_os_nothread_mutex_unlock
421781Sgtb # define k5_os_mutex_assert_locked	k5_os_nothread_mutex_assert_locked
422781Sgtb # define k5_os_mutex_assert_unlocked	k5_os_nothread_mutex_assert_unlocked
423781Sgtb 
424781Sgtb # define k5_once_t			k5_os_nothread_once_t
425781Sgtb # define K5_ONCE_INIT			K5_OS_NOTHREAD_ONCE_INIT
426781Sgtb # define k5_once			k5_os_nothread_once
427781Sgtb 
428781Sgtb #elif HAVE_PTHREAD
429781Sgtb 
430781Sgtb # include <pthread.h>
431781Sgtb 
432781Sgtb /* Weak reference support, etc.
433781Sgtb 
434781Sgtb    Linux: Stub mutex routines exist, but pthread_once does not.
435781Sgtb 
4367934SMark.Phalan@Sun.COM    Solaris: In libc there's a pthread_once that doesn't seem to do
4377934SMark.Phalan@Sun.COM    anything.  Bleah.  But pthread_mutexattr_setrobust_np is defined
4387934SMark.Phalan@Sun.COM    only in libpthread.  However, some version of GNU libc (Red Hat's
4397934SMark.Phalan@Sun.COM    Fedora Core 5, reportedly) seems to have that function, but no
4407934SMark.Phalan@Sun.COM    declaration, so we'd have to declare it in order to test for its
4417934SMark.Phalan@Sun.COM    address.  We now have tests to see if pthread_once actually works,
4427934SMark.Phalan@Sun.COM    so stick with that for now.
443781Sgtb 
444781Sgtb    IRIX 6.5 stub pthread support in libc is really annoying.  The
445781Sgtb    pthread_mutex_lock function returns ENOSYS for a program not linked
446781Sgtb    against -lpthread.  No link-time failure, no weak symbols, etc.
447781Sgtb    The C library doesn't provide pthread_once; we can use weak
448781Sgtb    reference support for that.
449781Sgtb 
450781Sgtb    If weak references are not available, then for now, we assume that
451781Sgtb    the pthread support routines will always be available -- either the
452781Sgtb    real thing, or functional stubs that merely prohibit creating
453781Sgtb    threads.
454781Sgtb 
455781Sgtb    If we find a platform with non-functional stubs and no weak
456781Sgtb    references, we may have to resort to some hack like dlsym on the
457781Sgtb    symbol tables of the current process.  */
458781Sgtb #ifdef HAVE_PRAGMA_WEAK_REF
459781Sgtb # pragma weak pthread_once
460781Sgtb # pragma weak pthread_mutex_lock
461781Sgtb # pragma weak pthread_mutex_unlock
462781Sgtb # pragma weak pthread_mutex_destroy
463781Sgtb # pragma weak pthread_mutex_init
464781Sgtb # pragma weak pthread_self
465781Sgtb # pragma weak pthread_equal
466781Sgtb # ifdef HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP_IN_THREAD_LIB
467781Sgtb #  pragma weak pthread_mutexattr_setrobust_np
468781Sgtb # endif
469781Sgtb # if !defined HAVE_PTHREAD_ONCE
470781Sgtb #  define K5_PTHREADS_LOADED	(&pthread_once != 0)
471781Sgtb # elif !defined HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP \
472781Sgtb 	&& defined HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP_IN_THREAD_LIB
473781Sgtb #  define K5_PTHREADS_LOADED	(&pthread_mutexattr_setrobust_np != 0)
474781Sgtb # else
475781Sgtb #  define K5_PTHREADS_LOADED	(1)
476781Sgtb # endif
477781Sgtb #else
478781Sgtb /* no pragma weak support */
479781Sgtb # define K5_PTHREADS_LOADED	(1)
480781Sgtb #endif
481781Sgtb 
482781Sgtb #if defined(__mips) && defined(__sgi) && (defined(_SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__))
483781Sgtb /* IRIX 6.5 stub pthread support in libc is really annoying.  The
484781Sgtb    pthread_mutex_lock function returns ENOSYS for a program not linked
485781Sgtb    against -lpthread.  No link-time failure, no weak reference tests,
486781Sgtb    etc.
487781Sgtb 
488781Sgtb    The C library doesn't provide pthread_once; we can use weak
489781Sgtb    reference support for that.  */
490781Sgtb # ifndef HAVE_PRAGMA_WEAK_REF
491781Sgtb #  if defined(__GNUC__) && __GNUC__ < 3
492781Sgtb #   error "Please update to a newer gcc with weak symbol support, or switch to native cc, reconfigure and recompile."
493781Sgtb #  else
494781Sgtb #   error "Weak reference support is required"
495781Sgtb #  endif
496781Sgtb # endif
497781Sgtb # define USE_PTHREAD_LOCK_ONLY_IF_LOADED
498781Sgtb #endif
499781Sgtb 
500781Sgtb #if !defined(HAVE_PTHREAD_MUTEX_LOCK) && !defined(USE_PTHREAD_LOCK_ONLY_IF_LOADED)
501781Sgtb # define USE_PTHREAD_LOCK_ONLY_IF_LOADED
502781Sgtb #endif
503781Sgtb 
504781Sgtb #ifdef HAVE_PRAGMA_WEAK_REF
505781Sgtb /* Can't rely on useful stubs -- see above regarding Solaris.  */
506781Sgtb typedef struct {
507781Sgtb     pthread_once_t o;
508781Sgtb     k5_os_nothread_once_t n;
509781Sgtb } k5_once_t;
510781Sgtb # define K5_ONCE_INIT	{ PTHREAD_ONCE_INIT, K5_OS_NOTHREAD_ONCE_INIT }
511781Sgtb # define k5_once(O,F)	(K5_PTHREADS_LOADED			\
512781Sgtb 			 ? pthread_once(&(O)->o,F)		\
513781Sgtb 			 : k5_os_nothread_once(&(O)->n,F))
514781Sgtb #else
515781Sgtb typedef pthread_once_t k5_once_t;
516781Sgtb # define K5_ONCE_INIT	PTHREAD_ONCE_INIT
517781Sgtb # define k5_once	pthread_once
518781Sgtb #endif
519781Sgtb 
520781Sgtb typedef struct {
521781Sgtb     pthread_mutex_t p;
522781Sgtb #ifdef DEBUG_THREADS
523781Sgtb     pthread_t owner;
524781Sgtb #endif
525781Sgtb #ifdef USE_PTHREAD_LOCK_ONLY_IF_LOADED
526781Sgtb     k5_os_nothread_mutex n;
527781Sgtb #endif
528781Sgtb } k5_os_mutex;
529781Sgtb 
530781Sgtb #ifdef DEBUG_THREADS
531781Sgtb # ifdef __GNUC__
532781Sgtb #  define k5_pthread_mutex_lock(M)			\
533781Sgtb 	({						\
534781Sgtb 	    k5_os_mutex *_m2 = (M);			\
535781Sgtb 	    int _r2 = pthread_mutex_lock(&_m2->p);	\
536781Sgtb 	    if (_r2 == 0) _m2->owner = pthread_self();	\
537781Sgtb 	    _r2;					\
538781Sgtb 	})
539781Sgtb # else
5407934SMark.Phalan@Sun.COM static int
k5_pthread_mutex_lock(k5_os_mutex * m)541781Sgtb k5_pthread_mutex_lock(k5_os_mutex *m)
542781Sgtb {
543781Sgtb     int r = pthread_mutex_lock(&m->p);
544781Sgtb     if (r)
545781Sgtb 	return r;
546781Sgtb     m->owner = pthread_self();
547781Sgtb     return 0;
548781Sgtb }
549781Sgtb # endif
550781Sgtb # define k5_pthread_assert_locked(M)				\
551781Sgtb 	(K5_PTHREADS_LOADED					\
552781Sgtb 	 ? ASSERT(pthread_equal((M)->owner, pthread_self()))	\
553781Sgtb 	 : (void)0)
554781Sgtb # define k5_pthread_mutex_unlock(M)	\
555781Sgtb 	(k5_pthread_assert_locked(M),	\
556781Sgtb 	 (M)->owner = (pthread_t) 0,	\
557781Sgtb 	 pthread_mutex_unlock(&(M)->p))
558781Sgtb #else
559781Sgtb # define k5_pthread_mutex_lock(M) pthread_mutex_lock(&(M)->p)
560781Sgtb /* LINTED */
k5_pthread_assert_locked(k5_os_mutex * m)561781Sgtb static void k5_pthread_assert_locked(k5_os_mutex *m) { }
562781Sgtb # define k5_pthread_mutex_unlock(M) pthread_mutex_unlock(&(M)->p)
563781Sgtb #endif
564781Sgtb 
565781Sgtb /* Define as functions to:
566781Sgtb    (1) eliminate "statement with no effect" warnings for "0"
567781Sgtb    (2) encourage type-checking in calling code  */
568781Sgtb 
569781Sgtb /* LINTED */
k5_pthread_assert_unlocked(pthread_mutex_t * m)570781Sgtb static void k5_pthread_assert_unlocked(pthread_mutex_t *m) { }
571781Sgtb 
572781Sgtb #if defined(DEBUG_THREADS_SLOW) && HAVE_SCHED_H && (HAVE_SCHED_YIELD || HAVE_PRAGMA_WEAK_REF)
573781Sgtb # include <sched.h>
574781Sgtb # if !HAVE_SCHED_YIELD
575781Sgtb #  pragma weak sched_yield
576781Sgtb #  define MAYBE_SCHED_YIELD()	((void)((&sched_yield != NULL) ? sched_yield() : 0))
577781Sgtb # else
578781Sgtb #  define MAYBE_SCHED_YIELD()	((void)sched_yield())
579781Sgtb # endif
580781Sgtb #else
581781Sgtb # define MAYBE_SCHED_YIELD()	((void)0)
582781Sgtb #endif
583781Sgtb 
584781Sgtb /* It may not be obvious why this function is desirable.
585781Sgtb 
586781Sgtb    I want to call pthread_mutex_lock, then sched_yield, then look at
587781Sgtb    the return code from pthread_mutex_lock.  That can't be implemented
588781Sgtb    in a macro without a temporary variable, or GNU C extensions.
589781Sgtb 
590781Sgtb    There used to be an inline function which did it, with both
591781Sgtb    functions called from the inline function.  But that messes with
592781Sgtb    the debug information on a lot of configurations, and you can't
593781Sgtb    tell where the inline function was called from.  (Typically, gdb
594781Sgtb    gives you the name of the function from which the inline function
595781Sgtb    was called, and a line number within the inline function itself.)
596781Sgtb 
597781Sgtb    With this auxiliary function, pthread_mutex_lock can be called at
598781Sgtb    the invoking site via a macro; once it returns, the inline function
599781Sgtb    is called (with messed-up line-number info for gdb hopefully
600781Sgtb    localized to just that call).  */
601781Sgtb #ifdef __GNUC__
602781Sgtb #define return_after_yield(R)			\
603781Sgtb 	__extension__ ({			\
604781Sgtb 	    int _r = (R);			\
605781Sgtb 	    MAYBE_SCHED_YIELD();		\
606781Sgtb 	    _r;					\
607781Sgtb 	})
608781Sgtb #else
return_after_yield(int r)609781Sgtb static int return_after_yield(int r)
610781Sgtb {
611781Sgtb     MAYBE_SCHED_YIELD();
612781Sgtb     return r;
613781Sgtb }
614781Sgtb #endif
615781Sgtb 
616781Sgtb #ifdef USE_PTHREAD_LOCK_ONLY_IF_LOADED
617781Sgtb 
618781Sgtb # if defined(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) && defined(DEBUG_THREADS)
619781Sgtb #  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
620781Sgtb 	{ PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, (pthread_t) 0, \
621781Sgtb 	  K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER }
622781Sgtb # elif defined(DEBUG_THREADS)
623781Sgtb #  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
624781Sgtb 	{ PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, \
625781Sgtb 	  K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER }
626781Sgtb # else
627781Sgtb #  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
628781Sgtb 	{ PTHREAD_MUTEX_INITIALIZER, K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER }
629781Sgtb # endif
6307934SMark.Phalan@Sun.COM asdfsdf
631781Sgtb # define k5_os_mutex_finish_init(M)		\
632781Sgtb 	k5_os_nothread_mutex_finish_init(&(M)->n)
633781Sgtb # define k5_os_mutex_init(M)			\
634781Sgtb 	(k5_os_nothread_mutex_init(&(M)->n),	\
635781Sgtb 	 (K5_PTHREADS_LOADED			\
636781Sgtb 	  ? pthread_mutex_init(&(M)->p, 0)	\
637781Sgtb 	  : 0))
638781Sgtb # define k5_os_mutex_destroy(M)			\
639781Sgtb 	(k5_os_nothread_mutex_destroy(&(M)->n),	\
640781Sgtb 	 (K5_PTHREADS_LOADED			\
641781Sgtb 	  ? pthread_mutex_destroy(&(M)->p)	\
642781Sgtb 	  : 0))
643781Sgtb 
644781Sgtb # define k5_os_mutex_lock(M)						\
645781Sgtb 	return_after_yield(K5_PTHREADS_LOADED				\
646781Sgtb 			   ? k5_pthread_mutex_lock(M)			\
647781Sgtb 			   : k5_os_nothread_mutex_lock(&(M)->n))
648781Sgtb # define k5_os_mutex_unlock(M)				\
649781Sgtb 	(MAYBE_SCHED_YIELD(),				\
650781Sgtb 	 (K5_PTHREADS_LOADED				\
651781Sgtb 	  ? k5_pthread_mutex_unlock(M)			\
652781Sgtb 	  : k5_os_nothread_mutex_unlock(&(M)->n)))
653781Sgtb 
654781Sgtb # define k5_os_mutex_assert_unlocked(M)			\
655781Sgtb 	(K5_PTHREADS_LOADED				\
656781Sgtb 	 ? k5_pthread_assert_unlocked(&(M)->p)		\
657781Sgtb 	 : k5_os_nothread_mutex_assert_unlocked(&(M)->n))
658781Sgtb # define k5_os_mutex_assert_locked(M)			\
659781Sgtb 	(K5_PTHREADS_LOADED				\
660781Sgtb 	 ? k5_pthread_assert_locked(M)			\
661781Sgtb 	 : k5_os_nothread_mutex_assert_locked(&(M)->n))
662781Sgtb 
663781Sgtb #else
664781Sgtb 
665781Sgtb # ifdef DEBUG_THREADS
666781Sgtb #  ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
667781Sgtb #   define K5_OS_MUTEX_PARTIAL_INITIALIZER \
668781Sgtb 	{ PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, (pthread_t) 0 }
669781Sgtb #  else
670781Sgtb #   define K5_OS_MUTEX_PARTIAL_INITIALIZER \
671781Sgtb 	{ PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0 }
672781Sgtb #  endif
673781Sgtb # else
674781Sgtb #  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
675781Sgtb 	{ PTHREAD_MUTEX_INITIALIZER }
676781Sgtb # endif
677781Sgtb 
678781Sgtb /* LINTED */
679781Sgtb static  int k5_os_mutex_finish_init(k5_os_mutex *m) { return 0; }
680781Sgtb # define k5_os_mutex_init(M)		pthread_mutex_init(&(M)->p, 0)
681781Sgtb # define k5_os_mutex_destroy(M)		pthread_mutex_destroy(&(M)->p)
682781Sgtb # define k5_os_mutex_lock(M)	return_after_yield(k5_pthread_mutex_lock(M))
683781Sgtb # define k5_os_mutex_unlock(M)		(MAYBE_SCHED_YIELD(),k5_pthread_mutex_unlock(M))
684781Sgtb 
685781Sgtb # define k5_os_mutex_assert_unlocked(M)	k5_pthread_assert_unlocked(&(M)->p)
686781Sgtb # define k5_os_mutex_assert_locked(M)	k5_pthread_assert_locked(M)
687781Sgtb 
688781Sgtb #endif /* is pthreads always available? */
689781Sgtb 
690781Sgtb #elif defined _WIN32
691781Sgtb 
692781Sgtb typedef struct {
693781Sgtb     HANDLE h;
694781Sgtb     int is_locked;
695781Sgtb } k5_os_mutex;
696781Sgtb 
697781Sgtb # define K5_OS_MUTEX_PARTIAL_INITIALIZER { INVALID_HANDLE_VALUE, 0 }
698781Sgtb 
699781Sgtb # define k5_os_mutex_finish_init(M)					 \
700781Sgtb 	(ASSERT((M)->h == INVALID_HANDLE_VALUE),			 \
701781Sgtb 	 ((M)->h = CreateMutex(NULL, FALSE, NULL)) ? 0 : GetLastError())
702781Sgtb # define k5_os_mutex_init(M)						 \
703781Sgtb 	((M)->is_locked = 0,						 \
704781Sgtb 	 ((M)->h = CreateMutex(NULL, FALSE, NULL)) ? 0 : GetLastError())
705781Sgtb # define k5_os_mutex_destroy(M)		\
706781Sgtb 	(CloseHandle((M)->h) ? ((M)->h = 0, 0) : GetLastError())
707781Sgtb 
7087934SMark.Phalan@Sun.COM static int k5_os_mutex_lock(k5_os_mutex *m)
709781Sgtb {
710781Sgtb     DWORD res;
711781Sgtb     res = WaitForSingleObject(m->h, INFINITE);
712781Sgtb     if (res == WAIT_FAILED)
713781Sgtb 	return GetLastError();
714781Sgtb     /* Eventually these should be turned into some reasonable error
715781Sgtb        code.  */
716781Sgtb     ASSERT(res != WAIT_TIMEOUT);
717781Sgtb     ASSERT(res != WAIT_ABANDONED);
718781Sgtb     ASSERT(res == WAIT_OBJECT_0);
719781Sgtb     /* Avoid locking twice.  */
720781Sgtb     ASSERT(m->is_locked == 0);
721781Sgtb     m->is_locked = 1;
722781Sgtb     return 0;
723781Sgtb }
724781Sgtb 
725781Sgtb # define k5_os_mutex_unlock(M)				\
726781Sgtb 	(ASSERT((M)->is_locked == 1),			\
727781Sgtb 	 (M)->is_locked = 0,				\
728781Sgtb 	 ReleaseMutex((M)->h) ? 0 : GetLastError())
729781Sgtb 
730781Sgtb # define k5_os_mutex_assert_unlocked(M)	((void)0)
731781Sgtb # define k5_os_mutex_assert_locked(M)	((void)0)
732781Sgtb 
733781Sgtb #else
734781Sgtb 
735781Sgtb # error "Thread support enabled, but thread system unknown"
736781Sgtb 
737781Sgtb #endif
738781Sgtb 
739781Sgtb 
740781Sgtb 
741781Sgtb 
742781Sgtb typedef struct {
743781Sgtb     k5_debug_loc loc_last, loc_created;
744781Sgtb     k5_os_mutex os;
745781Sgtb     k5_debug_mutex_stats stats;
746781Sgtb } k5_mutex_t;
747781Sgtb #define K5_MUTEX_PARTIAL_INITIALIZER		\
748781Sgtb 	{ K5_DEBUG_LOC_INIT, K5_DEBUG_LOC_INIT,	\
749781Sgtb 	  K5_OS_MUTEX_PARTIAL_INITIALIZER, K5_MUTEX_STATS_INIT }
750781Sgtb /* LINTED */
k5_mutex_init_1(k5_mutex_t * m,k5_debug_loc l)751781Sgtb static int k5_mutex_init_1(k5_mutex_t *m, k5_debug_loc l)
752781Sgtb {
753781Sgtb     int err = k5_os_mutex_init(&m->os);
754781Sgtb     if (err) return err;
755781Sgtb     m->loc_created = m->loc_last = l;
756781Sgtb     err = k5_mutex_init_stats(&m->stats);
757781Sgtb     ASSERT(err == 0);
758781Sgtb     return 0;
759781Sgtb }
760781Sgtb #define k5_mutex_init(M)	k5_mutex_init_1((M), K5_DEBUG_LOC)
761781Sgtb /* LINTED */
k5_mutex_finish_init_1(k5_mutex_t * m,k5_debug_loc l)762781Sgtb static  int k5_mutex_finish_init_1(k5_mutex_t *m, k5_debug_loc l)
763781Sgtb {
764781Sgtb     int err = k5_os_mutex_finish_init(&m->os);
765781Sgtb     if (err) return err;
766781Sgtb     m->loc_created = m->loc_last = l;
767781Sgtb     err = k5_mutex_finish_init_stats(&m->stats);
768781Sgtb     ASSERT(err == 0);
769781Sgtb     return 0;
770781Sgtb }
771781Sgtb #define k5_mutex_finish_init(M)	k5_mutex_finish_init_1((M), K5_DEBUG_LOC)
772781Sgtb #define k5_mutex_destroy(M)			\
773781Sgtb 	(k5_os_mutex_assert_unlocked(&(M)->os),	\
774781Sgtb 	 k5_mutex_lock(M), (M)->loc_last = K5_DEBUG_LOC, k5_mutex_unlock(M), \
775781Sgtb 	 k5_os_mutex_destroy(&(M)->os))
776781Sgtb #ifdef __GNUC__
777781Sgtb #define k5_mutex_lock(M)				\
778781Sgtb 	__extension__ ({				\
779781Sgtb 	    int _err = 0;				\
780781Sgtb 	    k5_mutex_t *_m = (M);			\
781781Sgtb 	    _err = k5_os_mutex_lock(&_m->os);		\
782781Sgtb 	    if (_err == 0) _m->loc_last = K5_DEBUG_LOC;	\
783781Sgtb 	    _err;					\
784781Sgtb 	})
785781Sgtb #else
786781Sgtb /* LINTED */
k5_mutex_lock_1(k5_mutex_t * m,k5_debug_loc l)787781Sgtb static  int k5_mutex_lock_1(k5_mutex_t *m, k5_debug_loc l)
788781Sgtb {
789781Sgtb     int err = 0;
790781Sgtb     err = k5_os_mutex_lock(&m->os);
791781Sgtb     if (err)
792781Sgtb 	return err;
793781Sgtb     m->loc_last = l;
794781Sgtb     return err;
795781Sgtb }
796781Sgtb #define k5_mutex_lock(M)	k5_mutex_lock_1(M, K5_DEBUG_LOC)
797781Sgtb #endif
798781Sgtb #define k5_mutex_unlock(M)				\
799781Sgtb 	(k5_mutex_assert_locked(M),			\
800781Sgtb 	 (M)->loc_last = K5_DEBUG_LOC,			\
801781Sgtb 	 k5_os_mutex_unlock(&(M)->os))
802781Sgtb 
803781Sgtb #define k5_mutex_assert_locked(M)	k5_os_mutex_assert_locked(&(M)->os)
804781Sgtb #define k5_mutex_assert_unlocked(M)	k5_os_mutex_assert_unlocked(&(M)->os)
805781Sgtb 
806781Sgtb #define k5_assert_locked	k5_mutex_assert_locked
807781Sgtb #define k5_assert_unlocked	k5_mutex_assert_unlocked
808781Sgtb 
809781Sgtb 
810781Sgtb /* Thread-specific data; implemented in a support file, because we'll
811781Sgtb    need to keep track of some global data for cleanup purposes.
812781Sgtb 
813781Sgtb    Note that the callback function type is such that the C library
814781Sgtb    routine free() is a valid callback.  */
815781Sgtb typedef enum {
816781Sgtb     K5_KEY_COM_ERR,
817781Sgtb     K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME,
818781Sgtb     K5_KEY_GSS_KRB5_CCACHE_NAME,
819*13132SGlenn.Barry@oracle.com     K5_KEY_GSS_KRB5_ERROR_MESSAGE,
820*13132SGlenn.Barry@oracle.com     K5_KEY_GSS_SPNEGO_ERROR_MESSAGE,
821781Sgtb     K5_KEY_MAX
822781Sgtb } k5_key_t;
823781Sgtb /* rename shorthand symbols for export */
824781Sgtb #define k5_key_register	krb5int_key_register
825781Sgtb #define k5_getspecific	krb5int_getspecific
826781Sgtb #define k5_setspecific	krb5int_setspecific
827781Sgtb #define k5_key_delete	krb5int_key_delete
828781Sgtb extern int k5_key_register(k5_key_t, void (*)(void *));
829781Sgtb extern void *k5_getspecific(k5_key_t);
830781Sgtb extern int k5_setspecific(k5_key_t, void *);
831781Sgtb extern int k5_key_delete(k5_key_t);
832781Sgtb 
8334960Swillf extern int  KRB5_CALLCONV krb5int_mutex_alloc  (k5_mutex_t **);
8344960Swillf extern void KRB5_CALLCONV krb5int_mutex_free   (k5_mutex_t *);
8354960Swillf extern int  KRB5_CALLCONV krb5int_mutex_lock   (k5_mutex_t *);
8364960Swillf extern int  KRB5_CALLCONV krb5int_mutex_unlock (k5_mutex_t *);
8374960Swillf 
8384960Swillf /* In time, many of the definitions above should move into the support
8394960Swillf    library, and this file should be greatly simplified.  For type
8404960Swillf    definitions, that'll take some work, since other data structures
8414960Swillf    incorporate mutexes directly, and our mutex type is dependent on
8424960Swillf    configuration options and system attributes.  For most functions,
8434960Swillf    though, it should be relatively easy.
8444960Swillf 
8454960Swillf    For now, plugins should use the exported functions, and not the
8464960Swillf    above macros, and use krb5int_mutex_alloc for allocations.  */
8474960Swillf #ifdef PLUGIN
8484960Swillf #undef k5_mutex_lock
8494960Swillf #define k5_mutex_lock krb5int_mutex_lock
8504960Swillf #undef k5_mutex_unlock
8514960Swillf #define k5_mutex_unlock krb5int_mutex_unlock
8524960Swillf #endif
8534960Swillf 
8545053Sgtb #endif /* _KERNEL */
8555053Sgtb 
8565053Sgtb 
857781Sgtb #endif /* multiple inclusion? */
858