From e7ed3790a13403db63d7f255c8266222c7fafa23 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Fri, 2 Jul 2004 22:16:56 +0000 Subject: [PATCH] * k5-thread.h: Restructured mutex code. (k5_debug_loc): New type, may contain file/line info if DEBUG_THREADS_LOC is defined. (k5_os_nothread_*): Dummy implementation of mutex lock for a single-threded process. Uses a flag and assert() if DEBUG_THREADS is defined, does nothing interesting otherwise. (k5_os_mutex*, k5_once*): General implementations, with dummy or POSIX or POSIX-if-loaded-otherwise-dummy variants. (k5_mutex_*): Combine OS-specific mutex implementation with optional file/line tracking, and provide a place to instrument for other debugging or performance data. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@16539 dc483132-0cff-0310-8789-dd5450dbe970 --- src/include/ChangeLog | 14 ++ src/include/k5-thread.h | 453 ++++++++++++++++++++++++---------------- 2 files changed, 292 insertions(+), 175 deletions(-) diff --git a/src/include/ChangeLog b/src/include/ChangeLog index 00c437d79..675e36258 100644 --- a/src/include/ChangeLog +++ b/src/include/ChangeLog @@ -1,3 +1,17 @@ +2004-07-02 Ken Raeburn + + * k5-thread.h: Restructured mutex code. + (k5_debug_loc): New type, may contain file/line info if + DEBUG_THREADS_LOC is defined. + (k5_os_nothread_*): Dummy implementation of mutex lock for a + single-threded process. Uses a flag and assert() if DEBUG_THREADS + is defined, does nothing interesting otherwise. + (k5_os_mutex*, k5_once*): General implementations, with dummy or + POSIX or POSIX-if-loaded-otherwise-dummy variants. + (k5_mutex_*): Combine OS-specific mutex implementation with + optional file/line tracking, and provide a place to instrument for + other debugging or performance data. + 2004-07-01 Ken Raeburn * configure.in: Test for 'inline' support. diff --git a/src/include/k5-thread.h b/src/include/k5-thread.h index a64f862d4..3619472a9 100644 --- a/src/include/k5-thread.h +++ b/src/include/k5-thread.h @@ -31,7 +31,7 @@ #include "autoconf.h" -/* Interface (tentative): + /* Interface (tentative): Mutex support: @@ -55,7 +55,6 @@ int k5_mutex_lock(k5_mutex_t *); int k5_mutex_unlock(k5_mutex_t *); - In each library, one new function to finish the static mutex init, and any other library-wide initialization that might be desired. On POSIX, this function would be called via the second support @@ -78,7 +77,6 @@ should also use atexit(). Any static mutexes should be cleaned up with k5_mutex_destroy here. - How does that second support function invoke the first support function only once? Through something modelled on pthread_once that I haven't written up yet. Probably: @@ -96,7 +94,7 @@ so I'm dropping the general scheme. Eventually the existing uses in k5-thread.h and k5-platform.h will be converted to pthread_once or static variables. - + Thread-specific data: @@ -143,150 +141,162 @@ #endif #define DEBUG_THREADS +#define DEBUG_THREADS_LOC #include -enum k5_mutex_debug_states { - K5_MUTEX_DEBUG_UNLOCKED = 34, - K5_MUTEX_DEBUG_LOCKED = 47 -}; + +/* For tracking locations, of (e.g.) last lock or unlock of mutex. */ +#ifdef DEBUG_THREADS_LOC typedef struct { const char *filename; - /* No source file in this tree gets anywhere near 32K lines. */ short lineno; - short initialized; - enum k5_mutex_debug_states locked; -} k5_mutex_debug_info; -#define K5_MUTEX_DEBUG_INITIALIZER { __FILE__, __LINE__, 2, K5_MUTEX_DEBUG_UNLOCKED } -#define k5_mutex_debug_finish_init(M) \ - (assert((M)->initialized == 2), (M)->initialized = 1, \ - k5_mutex_debug_update_loc(M), 0) -#define k5_mutex_debug_init(M) \ - ((M)->initialized = 1, \ - (M)->locked = K5_MUTEX_DEBUG_UNLOCKED, \ - k5_mutex_debug_update_loc(M), 0) -#define k5_mutex_debug_destroy(M) \ - (assert((M)->initialized == 1 \ - && (M)->locked == K5_MUTEX_DEBUG_UNLOCKED), \ - k5_mutex_debug_update_loc(M), \ - (M)->initialized = 0) -#define k5_mutex_debug_check_init(M) \ - (assert((M)->initialized != 2), \ - assert((M)->initialized != 0), \ - assert((M)->initialized == 1), 0) -#define k5_mutex_debug_update_loc(M) \ - ((M)->lineno = __LINE__, (M)->filename = __FILE__) -#define k5_mutex_debug_lock(M) \ - (k5_debug_assert_unlocked(M), \ - k5_mutex_debug_update_loc(M), \ +} k5_debug_loc; +#define K5_DEBUG_LOC_INIT { __FILE__, __LINE__ } +#if __GNUC__ >= 2 +#define K5_DEBUG_LOC (__extension__ (k5_debug_loc)K5_DEBUG_LOC_INIT) +#else +static inline k5_debug_loc k5_debug_make_loc(const char *file, short line) +{ + k5_debug_loc l; + l.filename = file; + l.lineno = line; + return l; +} +#define K5_DEBUG_LOC (k5_debug_make_loc(__FILE__,__LINE__)) +#endif +#else /* ! DEBUG_THREADS_LOC */ +typedef char k5_debug_loc; +#define K5_DEBUG_LOC_INIT 0 +#define K5_DEBUG_LOC 0 +#endif + +#define k5_debug_update_loc(L) ((L) = K5_DEBUG_LOC) + + + +/* Define the OS mutex bit. */ + +/* First, if we're not actually doing multiple threads, do we + want the debug support or not? */ + +#ifdef DEBUG_THREADS + +enum k5_mutex_init_states { + K5_MUTEX_DEBUG_PARTLY_INITIALIZED = 0x12, + K5_MUTEX_DEBUG_INITIALIZED, + K5_MUTEX_DEBUG_DESTROYED +}; +enum k5_mutex_flag_states { + K5_MUTEX_DEBUG_UNLOCKED = 0x23, + K5_MUTEX_DEBUG_LOCKED +}; + +typedef struct { + enum k5_mutex_init_states initialized; + enum k5_mutex_flag_states locked; +} k5_os_nothread_mutex; + +# define K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER \ + { K5_MUTEX_DEBUG_PARTLY_INITIALIZED, K5_MUTEX_DEBUG_UNLOCKED } + +# define k5_os_nothread_mutex_finish_init(M) \ + (assert((M)->initialized != K5_MUTEX_DEBUG_INITIALIZED), \ + assert((M)->initialized == K5_MUTEX_DEBUG_PARTLY_INITIALIZED), \ + assert((M)->locked == K5_MUTEX_DEBUG_UNLOCKED), \ + (M)->initialized = K5_MUTEX_DEBUG_INITIALIZED, 0) +# define k5_os_nothread_mutex_init(M) \ + ((M)->initialized = K5_MUTEX_DEBUG_INITIALIZED, \ + (M)->locked = K5_MUTEX_DEBUG_UNLOCKED, 0) +# define k5_os_nothread_mutex_destroy(M) \ + (assert((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED), \ + (M)->initialized = K5_MUTEX_DEBUG_DESTROYED, 0) + +# define k5_os_nothread_mutex_lock(M) \ + (k5_os_nothread_mutex_assert_unlocked(M), \ (M)->locked = K5_MUTEX_DEBUG_LOCKED, 0) -#define k5_mutex_debug_unlock(M) \ - (k5_debug_assert_locked(M), \ - k5_mutex_debug_update_loc(M), \ +# define k5_os_nothread_mutex_unlock(M) \ + (k5_os_nothread_mutex_assert_locked(M), \ (M)->locked = K5_MUTEX_DEBUG_UNLOCKED, 0) -#define k5_debug_assert_locked(M) \ - (k5_mutex_debug_check_init(M), \ - assert((M)->locked != K5_MUTEX_DEBUG_UNLOCKED), \ + +# define k5_os_nothread_mutex_assert_locked(M) \ + (assert((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED), \ + assert((M)->locked != K5_MUTEX_DEBUG_UNLOCKED), \ assert((M)->locked == K5_MUTEX_DEBUG_LOCKED), 0) -#define k5_debug_assert_unlocked(M) \ - (k5_mutex_debug_check_init(M), \ +# define k5_os_nothread_mutex_assert_unlocked(M) \ + (assert((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED), \ + assert((M)->locked != K5_MUTEX_DEBUG_LOCKED), \ assert((M)->locked == K5_MUTEX_DEBUG_UNLOCKED), 0) -typedef enum { - K5_KEY_COM_ERR, - K5_KEY_MAX -} k5_key_t; - +#else /* threads disabled and not debugging */ -#ifdef ENABLE_THREADS +typedef char k5_os_nothread_mutex; +# define K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER 0 +# define k5_os_nothread_mutex_finish_init(M) (0) +# define k5_os_nothread_mutex_init(M) (0) +# define k5_os_nothread_mutex_destroy(M) (0) +# define k5_os_nothread_mutex_lock(M) (0) +# define k5_os_nothread_mutex_unlock(M) (0) +# define k5_os_nothread_mutex_assert_locked(M) (0) +# define k5_os_nothread_mutex_assert_unlocked(M) (0) -#ifdef HAVE_PTHREAD_H - -#include - -/* To do: Weak symbol support. Windows threads. +#endif - Mutex initialization may need to be re-thought if we find we want - any non-default attributes, like priority inheritance. */ +/* Values: + 2 - function has not been run + 3 - function has been run + 4 - function is being run -- deadlock detected */ +typedef unsigned char k5_os_nothread_once_t; +# define K5_OS_NOTHREAD_ONCE_INIT 2 +# define k5_os_nothread_once(O,F) \ + (*(O) == 3 ? 0 \ + : *(O) == 2 ? (*(O) = 4, (F)(), *(O) = 3, 0) \ + : (assert(*(O) != 4), assert(*(O) == 2 || *(O) == 3), 0)) -#ifndef DEBUG_THREADS -typedef pthread_mutex_t k5_mutex_t; -#define K5_MUTEX_PARTIAL_INITIALIZER PTHREAD_MUTEX_INITIALIZER -#define k5_mutex_finish_init(M) ((void)(M),0) -#define k5_mutex_init(M) pthread_mutex_init(M, 0) -#define k5_mutex_destroy(M) pthread_mutex_destroy(M) -#define k5_mutex_lock(M) pthread_mutex_lock(M) -#define k5_mutex_unlock(M) pthread_mutex_unlock(M) -#define k5_assert_locked(M) (0) -#define k5_assert_unlocked(M) (0) +#ifndef ENABLE_THREADS -#else /* DEBUG_THREADS */ +typedef k5_os_nothread_mutex k5_os_mutex; +# define K5_OS_MUTEX_PARTIAL_INITIALIZER \ + K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER +# define k5_os_mutex_finish_init k5_os_nothread_mutex_finish_init +# define k5_os_mutex_init k5_os_nothread_mutex_init +# define k5_os_mutex_destroy k5_os_nothread_mutex_destroy +# define k5_os_mutex_lock k5_os_nothread_mutex_lock +# define k5_os_mutex_unlock k5_os_nothread_mutex_unlock +# define k5_os_mutex_assert_locked k5_os_nothread_mutex_assert_locked +# define k5_os_mutex_assert_unlocked k5_os_nothread_mutex_assert_unlocked -typedef struct { - k5_mutex_debug_info debug; - pthread_mutex_t lock; -} k5_mutex_t; -#define K5_MUTEX_PARTIAL_INITIALIZER \ - { K5_MUTEX_DEBUG_INITIALIZER, PTHREAD_MUTEX_INITIALIZER } -#define k5_mutex_finish_init(M) (k5_mutex_debug_finish_init(&(M)->debug)) -#define k5_mutex_init(M) (k5_mutex_debug_init(&(M)->debug), \ - assert(0==pthread_mutex_init(&(M)->lock,0)), \ - 0) -#define k5_mutex_destroy(M) (k5_mutex_debug_init(&(M)->debug), \ - assert(0==pthread_mutex_destroy(&(M)->lock))) -#define k5_mutex_lock(M) (k5_mutex_debug_check_init(&(M)->debug), \ - assert(0==pthread_mutex_lock(&(M)->lock)), \ - assert((M)->debug.locked \ - == K5_MUTEX_DEBUG_UNLOCKED), \ - k5_mutex_debug_update_loc(&(M)->debug), \ - (M)->debug.locked = K5_MUTEX_DEBUG_LOCKED, \ - 0) -#define k5_mutex_unlock(M) (k5_mutex_debug_check_init(&(M)->debug), \ - assert((M)->debug.locked \ - == K5_MUTEX_DEBUG_LOCKED), \ - k5_mutex_debug_update_loc(&(M)->debug), \ - (M)->debug.locked = K5_MUTEX_DEBUG_UNLOCKED, \ - assert(0==pthread_mutex_unlock(&(M)->lock)), \ - 0) -#define k5_assert_locked(M) (k5_debug_assert_locked(&(M)->debug)) -#define k5_assert_unlocked(M) (k5_debug_assert_unlocked(&(M)->debug)) +# define k5_once_t k5_os_nothread_once_t +# define K5_ONCE_INIT K5_OS_NOTHREAD_ONCE_INIT +# define k5_once k5_os_nothread_once -#if defined(__mips) && defined(__sgi) && (defined(_SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__)) -/* IRIX 6.5 stub pthread support in libc is really annoying. - The pthread_mutex_lock function returns ENOSYS for a program - not linked against -lpthread. No link-time failure, no weak - symbols, etc. +#elif HAVE_PTHREAD_H - The C library doesn't provide pthread_once; we can use weak - reference support for that. */ -#if defined(__GNUC__) && __GNUC__ < 3 -# error "Please update to a newer gcc with weak symbol support, or switch to native cc; reconfigure and recompile." -#endif -#undef k5_mutex_lock -#undef k5_mutex_unlock -#define k5_mutex_lock(M) \ - (k5_mutex_debug_lock(&(M)->debug), \ - (K5_PTHREADS_LOADED \ - ? pthread_mutex_lock(&(M)->lock) \ - : 0)) -#define k5_mutex_unlock(M) \ - (k5_mutex_debug_unlock(&(M)->debug), \ - (K5_PTHREADS_LOADED \ - ? pthread_mutex_unlock(&(M)->lock) \ - : 0)) -#endif +# include -#endif /* DEBUG_THREADS ? */ +/* Weak reference support, etc. -/* Linux with weak reference support: - Stub mutex routines exist, but pthread_once does not. + Linux: Stub mutex routines exist, but pthread_once does not. Solaris: In libc there's a pthread_once that doesn't seem to do anything. Bleah. But pthread_mutexattr_setrobust_np is defined only in libpthread. - */ + IRIX 6.5 stub pthread support in libc is really annoying. The + pthread_mutex_lock function returns ENOSYS for a program not linked + against -lpthread. No link-time failure, no weak symbols, etc. + The C library doesn't provide pthread_once; we can use weak + reference support for that. + + If weak references are not available, then for now, we assume that + the pthread support routines will always be available -- either the + real thing, or functional stubs that merely prohibit creating + threads. + + If we find a platform with non-functional stubs and no weak + references, we may have to resort to some hack like dlsym on the + symbol tables of the current process. */ #ifdef HAVE_PRAGMA_WEAK_REF # pragma weak pthread_once # ifdef HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP_IN_THREAD_LIB @@ -305,80 +315,173 @@ typedef struct { # define K5_PTHREADS_LOADED (1) #endif -/* Would be nice to use a union, but we need to initialize both. */ +#if defined(__mips) && defined(__sgi) && (defined(_SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__)) +/* IRIX 6.5 stub pthread support in libc is really annoying. The + pthread_mutex_lock function returns ENOSYS for a program not linked + against -lpthread. No link-time failure, no weak reference tests, + etc. + + The C library doesn't provide pthread_once; we can use weak + reference support for that. */ +# ifndef HAVE_PRAGMA_WEAK_REF +# if defined(__GNUC__) && __GNUC__ < 3 +# error "Please update to a newer gcc with weak symbol support, or switch to native cc, reconfigure and recompile." +# else +# error "Weak reference support is required" +# endif +# endif +# define USE_PTHREAD_LOCK_ONLY_IF_LOADED +#endif + #ifdef HAVE_PRAGMA_WEAK_REF -typedef struct { pthread_once_t o; int i; } k5_once_t; -#define K5_ONCE_INIT { PTHREAD_ONCE_INIT, 2 } -#define k5_once(O,F) (K5_PTHREADS_LOADED \ - ? pthread_once(&(O)->o,F) \ - : (O)->i == 2 \ - ? ((O)->i = 3, (*F)(), 0) \ - : 0) +/* Can't rely on useful stubs -- see above regarding Solaris. */ +typedef struct { + pthread_once_t o; + k5_os_nothread_once_t n; +} k5_once_t; +# define K5_ONCE_INIT { PTHREAD_ONCE_INIT, K5_OS_NOTHREAD_ONCE_INIT } +# define k5_once(O,F) (K5_PTHREADS_LOADED \ + ? pthread_once(&(O)->o,F) \ + : k5_os_nothread_once(&(O)->n,F)) #else typedef pthread_once_t k5_once_t; -#define K5_ONCE_INIT PTHREAD_ONCE_INIT -#define k5_once pthread_once +# define K5_ONCE_INIT PTHREAD_ONCE_INIT +# define k5_once pthread_once #endif -#elif defined(_WIN32) - -# error "Windows thread support not implemented yet" -/* N.B.: No k5_once support for this platform. */ +typedef struct { + pthread_mutex_t p; +#ifdef USE_PTHREAD_LOCK_ONLY_IF_LOADED + k5_os_nothread_mutex n; +#endif +} k5_os_mutex; + +#define k5_pthread_assert_unlocked(M) (0) +#define k5_pthread_assert_locked(M) (0) + +#ifdef USE_PTHREAD_LOCK_ONLY_IF_LOADED + +# define K5_OS_MUTEX_PARTIAL_INITIALIZER \ + { PTHREAD_MUTEX_INITIALIZER, K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER } + +# define k5_os_mutex_finish_init(M) \ + k5_os_nothread_mutex_finish_init(&(M)->n) +# define k5_os_mutex_init(M) \ + (k5_os_nothread_mutex_init(&(M)->n), \ + pthread_mutex_init(&(M)->p, 0)) +# define k5_os_mutex_destroy(M) \ + (k5_os_nothread_mutex_destroy(&(M)->n), \ + pthread_mutex_destroy(&(M)->p)) + +# define k5_os_mutex_lock(M) \ + (K5_PTHREADS_LOADED \ + ? pthread_mutex_lock(&(M)->p) \ + : k5_os_nothread_lock(&(M)->n)) +# define k5_os_mutex_unlock(M) \ + (K5_PTHREADS_LOADED \ + ? pthread_mutex_unlock(&(M)->p) \ + : k5_os_nothread_unlock(&(M)->n)) + +# define k5_os_mutex_assert_unlocked(M) \ + (K5_PTHREADS_LOADED \ + ? k5_pthread_assert_unlocked(&(M)->p) \ + : k5_os_nothread_assert_unlocked(&(M)->n)) +# define k5_os_mutex_assert_locked(M) \ + (K5_PTHREADS_LOADED \ + ? k5_pthread_assert_locked(&(M)->p) \ + : k5_os_nothread_assert_locked(&(M)->n)) #else -# error "Thread support enabled, but thread system unknown" +# define K5_OS_MUTEX_PARTIAL_INITIALIZER \ + { PTHREAD_MUTEX_INITIALIZER } -#endif +# define k5_os_mutex_finish_init(M) (0) +# define k5_os_mutex_init(M) pthread_mutex_init(&(M)->p, 0) +# define k5_os_mutex_destroy(M) pthread_mutex_destroy(&(M)->p) -#else /* ! ENABLE_THREADS */ +# define k5_os_mutex_lock(M) pthread_mutex_lock(&(M)->p) +# define k5_os_mutex_unlock(M) pthread_mutex_unlock(&(M)->p) -#ifdef DEBUG_THREADS +# define k5_os_mutex_assert_unlocked(M) k5_pthread_assert_unlocked(&(M)->p) +# define k5_os_mutex_assert_locked(M) k5_pthread_assert_locked(&(M)->p) -#include +#endif /* is pthreads always available? */ -/* Even if not using threads, use some mutex-like locks to see if - we're pairing up lock and unlock calls properly. */ +#elif defined _WIN32 -#define k5_mutex_t k5_mutex_debug_info -#define K5_MUTEX_PARTIAL_INITIALIZER K5_MUTEX_DEBUG_INITIALIZER -#define k5_mutex_finish_init k5_mutex_debug_finish_init -#define k5_mutex_init k5_mutex_debug_init -#define k5_mutex_destroy k5_mutex_debug_destroy -#define k5_mutex_lock k5_mutex_debug_lock -#define k5_mutex_unlock k5_mutex_debug_unlock -#define k5_assert_locked k5_debug_assert_locked -#define k5_assert_unlocked k5_debug_assert_unlocked - -#define k5_once_t unsigned char -#define K5_ONCE_INIT 2 -#define k5_once(O,F) \ - (assert(*(O) == 2 || *(O) == 3), \ - (*(O) == 3 ? 0 : ((F)(), *(O) = 3, 0))) - -#else /* ! DEBUG_THREADS */ +# error "Windows thread support not implemented yet" -/* no-op versions */ +#else -typedef char k5_mutex_t; -#define K5_MUTEX_PARTIAL_INITIALIZER 0 -#define k5_mutex_finish_init(M) (0) -#define k5_mutex_init(M) (*(M) = 0, *(M) = *(M)) -#define k5_mutex_destroy(M) (0) -#define k5_mutex_lock(M) (0) -#define k5_mutex_unlock(M) (0) -#define k5_assert_locked(M) (0) -#define k5_assert_unlocked(M) (0) +# error "Thread support enabled, but thread system unknown" -#define k5_once_t unsigned char -#define K5_ONCE_INIT 2 -#define k5_once(F,O) \ - (*(O) == 3 ? 0 : ((F)(), *(O) = 3, 0)) +#endif -#endif /* DEBUG_THREADS ? */ -#endif /* ENABLE_THREADS ? */ + +typedef struct { + k5_debug_loc loc_last, loc_created; + k5_os_mutex os; +} k5_mutex_t; +#define K5_MUTEX_PARTIAL_INITIALIZER \ + { K5_DEBUG_LOC_INIT, K5_DEBUG_LOC_INIT, \ + K5_OS_MUTEX_PARTIAL_INITIALIZER } +static inline int k5_mutex_init_1(k5_mutex_t *m, k5_debug_loc l) +{ + int err = k5_os_mutex_init(&m->os); + if (err) return err; + m->loc_created = m->loc_last = l; + return 0; +} +#define k5_mutex_init(M) k5_mutex_init_1((M), K5_DEBUG_LOC) +static inline int k5_mutex_finish_init_1(k5_mutex_t *m, k5_debug_loc l) +{ + int err = k5_os_mutex_finish_init(&m->os); + if (err) return err; + m->loc_created = m->loc_last = l; + return 0; +} +#define k5_mutex_finish_init(M) k5_mutex_finish_init_1((M), K5_DEBUG_LOC) +#define k5_mutex_destroy(M) \ + (k5_os_mutex_assert_unlocked(&(M)->os), \ + (M)->loc_last = K5_DEBUG_LOC, \ + k5_os_mutex_destroy(&(M)->os)) +static inline int k5_mutex_lock_1(k5_mutex_t *m, k5_debug_loc l) +{ + int err = 0; + err = k5_os_mutex_lock(&m->os); + if (err) + return err; + m->loc_last = l; + return err; +} +#define k5_mutex_lock(M) k5_mutex_lock_1(M, K5_DEBUG_LOC) +static inline int k5_mutex_unlock_1(k5_mutex_t *m, k5_debug_loc l) +{ + int err = 0; + err = k5_os_mutex_unlock(&m->os); + if (err) + return err; + m->loc_last = l; + return err; +} +#define k5_mutex_unlock(M) k5_mutex_unlock_1(M, K5_DEBUG_LOC) + +#define k5_mutex_assert_locked(M) k5_os_mutex_assert_locked(&(M)->os) +#define k5_mutex_assert_unlocked(M) k5_os_mutex_assert_unlocked(&(M)->os) + +#define k5_assert_locked k5_mutex_assert_locked +#define k5_assert_unlocked k5_mutex_assert_unlocked + + +/* Thread-specific data; implemented in a support file, because we'll + need to keep track of some global data for cleanup purposes. */ +typedef enum { + K5_KEY_COM_ERR, + K5_KEY_MAX +} k5_key_t; /* rename shorthand symbols for export */ #define k5_key_register krb5int_key_register #define k5_getspecific krb5int_getspecific -- 2.26.2