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