|
Packit |
fd8b60 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
fd8b60 |
/* include/k5-thread.h - Preliminary portable thread support */
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Copyright 2004,2005,2006,2007,2008 by the Massachusetts Institute of Technology.
|
|
Packit |
fd8b60 |
* All Rights Reserved.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Export of this software from the United States of America may
|
|
Packit |
fd8b60 |
* require a specific license from the United States Government.
|
|
Packit |
fd8b60 |
* It is the responsibility of any person or organization contemplating
|
|
Packit |
fd8b60 |
* export to obtain such a license before exporting.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
|
Packit |
fd8b60 |
* distribute this software and its documentation for any purpose and
|
|
Packit |
fd8b60 |
* without fee is hereby granted, provided that the above copyright
|
|
Packit |
fd8b60 |
* notice appear in all copies and that both that copyright notice and
|
|
Packit |
fd8b60 |
* this permission notice appear in supporting documentation, and that
|
|
Packit |
fd8b60 |
* the name of M.I.T. not be used in advertising or publicity pertaining
|
|
Packit |
fd8b60 |
* to distribution of the software without specific, written prior
|
|
Packit |
fd8b60 |
* permission. Furthermore if you modify this software you must label
|
|
Packit |
fd8b60 |
* your software as modified software and not distribute it in such a
|
|
Packit |
fd8b60 |
* fashion that it might be confused with the original M.I.T. software.
|
|
Packit |
fd8b60 |
* M.I.T. makes no representations about the suitability of
|
|
Packit |
fd8b60 |
* this software for any purpose. It is provided "as is" without express
|
|
Packit |
fd8b60 |
* or implied warranty.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifndef K5_THREAD_H
|
|
Packit |
fd8b60 |
#define K5_THREAD_H
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include "autoconf.h"
|
|
Packit |
fd8b60 |
#ifndef KRB5_CALLCONV
|
|
Packit |
fd8b60 |
# define KRB5_CALLCONV
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
#ifndef KRB5_CALLCONV_C
|
|
Packit |
fd8b60 |
# define KRB5_CALLCONV_C
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Interface (tentative):
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
Mutex support:
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
// Between these two, we should be able to do pure compile-time
|
|
Packit |
fd8b60 |
// and pure run-time initialization.
|
|
Packit |
fd8b60 |
// POSIX: partial initializer is PTHREAD_MUTEX_INITIALIZER,
|
|
Packit |
fd8b60 |
// finish does nothing
|
|
Packit |
fd8b60 |
// Windows: partial initializer is an invalid handle,
|
|
Packit |
fd8b60 |
// finish does the real initialization work
|
|
Packit |
fd8b60 |
k5_mutex_t foo_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
|
|
Packit |
fd8b60 |
int k5_mutex_finish_init(k5_mutex_t *);
|
|
Packit |
fd8b60 |
// for dynamic allocation
|
|
Packit |
fd8b60 |
int k5_mutex_init(k5_mutex_t *);
|
|
Packit |
fd8b60 |
// Must work for both kinds of alloc, even if it means adding flags.
|
|
Packit |
fd8b60 |
int k5_mutex_destroy(k5_mutex_t *);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
// As before.
|
|
Packit |
fd8b60 |
int k5_mutex_lock(k5_mutex_t *);
|
|
Packit |
fd8b60 |
int k5_mutex_unlock(k5_mutex_t *);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
In each library, one new function to finish the static mutex init,
|
|
Packit |
fd8b60 |
and any other library-wide initialization that might be desired.
|
|
Packit |
fd8b60 |
On POSIX, this function would be called via the second support
|
|
Packit |
fd8b60 |
function (see below). On Windows, it would be called at library
|
|
Packit |
fd8b60 |
load time. These functions, or functions they calls, should be the
|
|
Packit |
fd8b60 |
only places that k5_mutex_finish_init gets called.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
A second function or macro called at various possible "first" entry
|
|
Packit |
fd8b60 |
points which either calls pthread_once on the first function
|
|
Packit |
fd8b60 |
(POSIX), or checks some flag set by the first function (Windows),
|
|
Packit |
fd8b60 |
and possibly returns an error. (In the non-threaded case, a simple
|
|
Packit |
fd8b60 |
flag can be used to avoid multiple invocations, and the mutexes
|
|
Packit |
fd8b60 |
don't need run-time initialization anyways.)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
A third function for library termination calls mutex_destroy on
|
|
Packit |
fd8b60 |
each mutex for the library. This function would be called
|
|
Packit |
fd8b60 |
automatically at library unload time. If it turns out to be needed
|
|
Packit |
fd8b60 |
at exit time for libraries that don't get unloaded, perhaps we
|
|
Packit |
fd8b60 |
should also use atexit(). Any static mutexes should be cleaned up
|
|
Packit |
fd8b60 |
with k5_mutex_destroy here.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
How does that second support function invoke the first support
|
|
Packit |
fd8b60 |
function only once? Through something modelled on pthread_once
|
|
Packit |
fd8b60 |
that I haven't written up yet. Probably:
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
k5_once_t foo_once = K5_ONCE_INIT;
|
|
Packit |
fd8b60 |
k5_once(k5_once_t *, void (*)(void));
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
For POSIX: Map onto pthread_once facility.
|
|
Packit |
fd8b60 |
For non-threaded case: A simple flag.
|
|
Packit |
fd8b60 |
For Windows: Not needed; library init code takes care of it.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
XXX: A general k5_once mechanism isn't possible for Windows,
|
|
Packit |
fd8b60 |
without faking it through named mutexes or mutexes initialized at
|
|
Packit |
fd8b60 |
startup. I was only using it in one place outside these headers,
|
|
Packit |
fd8b60 |
so I'm dropping the general scheme. Eventually the existing uses
|
|
Packit |
fd8b60 |
in k5-thread.h and k5-platform.h will be converted to pthread_once
|
|
Packit |
fd8b60 |
or static variables.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
Thread-specific data:
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
// TSD keys are limited in number in gssapi/krb5/com_err; enumerate
|
|
Packit |
fd8b60 |
// them all. This allows support code init to allocate the
|
|
Packit |
fd8b60 |
// necessary storage for pointers all at once, and avoids any
|
|
Packit |
fd8b60 |
// possible error in key creation.
|
|
Packit |
fd8b60 |
enum { ... } k5_key_t;
|
|
Packit |
fd8b60 |
// Register destructor function. Called in library init code.
|
|
Packit |
fd8b60 |
int k5_key_register(k5_key_t, void (*destructor)(void *));
|
|
Packit |
fd8b60 |
// Returns NULL or data.
|
|
Packit |
fd8b60 |
void *k5_getspecific(k5_key_t);
|
|
Packit |
fd8b60 |
// Returns error if key out of bounds, or the pointer table can't
|
|
Packit |
fd8b60 |
// be allocated. A call to k5_key_register must have happened first.
|
|
Packit |
fd8b60 |
// This may trigger the calling of pthread_setspecific on POSIX.
|
|
Packit |
fd8b60 |
int k5_setspecific(k5_key_t, void *);
|
|
Packit |
fd8b60 |
// Called in library termination code.
|
|
Packit |
fd8b60 |
// Trashes data in all threads, calling the registered destructor
|
|
Packit |
fd8b60 |
// (but calling it from the current thread).
|
|
Packit |
fd8b60 |
int k5_key_delete(k5_key_t);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
For the non-threaded version, the support code will have a static
|
|
Packit |
fd8b60 |
array indexed by k5_key_t values, and get/setspecific simply access
|
|
Packit |
fd8b60 |
the array elements.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
The TSD destructor table is global state, protected by a mutex if
|
|
Packit |
fd8b60 |
threads are enabled.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
Any actual external symbols will use the krb5int_ prefix. The k5_
|
|
Packit |
fd8b60 |
names will be simple macros or inline functions to rename the
|
|
Packit |
fd8b60 |
external symbols, or slightly more complex ones to expand the
|
|
Packit |
fd8b60 |
implementation inline (e.g., map to POSIX versions and/or debug
|
|
Packit |
fd8b60 |
code using __FILE__ and the like).
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
More to be added, perhaps. */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <assert.h>
|
|
Packit |
fd8b60 |
#ifndef NDEBUG
|
|
Packit |
fd8b60 |
#include <stdio.h>
|
|
Packit |
fd8b60 |
#include <string.h>
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* The mutex structure we use, k5_mutex_t, is defined to some
|
|
Packit |
fd8b60 |
OS-specific bits. The use of multiple layers of typedefs are an
|
|
Packit |
fd8b60 |
artifact resulting from debugging code we once used, implemented as
|
|
Packit |
fd8b60 |
wrappers around the OS mutex scheme.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
The OS specific bits, in k5_os_mutex, break down into three primary
|
|
Packit |
fd8b60 |
implementations, POSIX threads, Windows threads, and no thread
|
|
Packit |
fd8b60 |
support. However, the POSIX thread version is further subdivided:
|
|
Packit |
fd8b60 |
In one case, we can determine at run time whether the thread
|
|
Packit |
fd8b60 |
library is linked into the application, and use it only if it is
|
|
Packit |
fd8b60 |
present; in the other case, we cannot, and the thread library must
|
|
Packit |
fd8b60 |
be linked in always, but can be used unconditionally. In the
|
|
Packit |
fd8b60 |
former case, the k5_os_mutex structure needs to hold both the POSIX
|
|
Packit |
fd8b60 |
and the non-threaded versions.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
The various k5_os_mutex_* operations are the OS-specific versions,
|
|
Packit |
fd8b60 |
applied to the OS-specific data, and k5_mutex_* uses k5_os_mutex_*
|
|
Packit |
fd8b60 |
to do the OS-specific parts of the work. */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Define the OS mutex bit. */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
typedef char k5_os_nothread_mutex;
|
|
Packit |
fd8b60 |
# define K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER 0
|
|
Packit |
fd8b60 |
/* Empty inline functions avoid the "statement with no effect"
|
|
Packit |
fd8b60 |
warnings, and do better type-checking than functions that don't use
|
|
Packit |
fd8b60 |
their arguments. */
|
|
Packit |
fd8b60 |
static inline int k5_os_nothread_mutex_finish_init(k5_os_nothread_mutex *m) {
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
static inline int k5_os_nothread_mutex_init(k5_os_nothread_mutex *m) {
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
static inline int k5_os_nothread_mutex_destroy(k5_os_nothread_mutex *m) {
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
static inline int k5_os_nothread_mutex_lock(k5_os_nothread_mutex *m) {
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
static inline int k5_os_nothread_mutex_unlock(k5_os_nothread_mutex *m) {
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Values:
|
|
Packit |
fd8b60 |
2 - function has not been run
|
|
Packit |
fd8b60 |
3 - function has been run
|
|
Packit |
fd8b60 |
4 - function is being run -- deadlock detected */
|
|
Packit |
fd8b60 |
typedef unsigned char k5_os_nothread_once_t;
|
|
Packit |
fd8b60 |
# define K5_OS_NOTHREAD_ONCE_INIT 2
|
|
Packit |
fd8b60 |
# define k5_os_nothread_once(O,F) \
|
|
Packit |
fd8b60 |
(*(O) == 3 ? 0 \
|
|
Packit |
fd8b60 |
: *(O) == 2 ? (*(O) = 4, (F)(), *(O) = 3, 0) \
|
|
Packit |
fd8b60 |
: (assert(*(O) != 4), assert(*(O) == 2 || *(O) == 3), 0))
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifndef ENABLE_THREADS
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
typedef k5_os_nothread_mutex k5_os_mutex;
|
|
Packit |
fd8b60 |
# define K5_OS_MUTEX_PARTIAL_INITIALIZER \
|
|
Packit |
fd8b60 |
K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER
|
|
Packit |
fd8b60 |
# define k5_os_mutex_finish_init k5_os_nothread_mutex_finish_init
|
|
Packit |
fd8b60 |
# define k5_os_mutex_init k5_os_nothread_mutex_init
|
|
Packit |
fd8b60 |
# define k5_os_mutex_destroy k5_os_nothread_mutex_destroy
|
|
Packit |
fd8b60 |
# define k5_os_mutex_lock k5_os_nothread_mutex_lock
|
|
Packit |
fd8b60 |
# define k5_os_mutex_unlock k5_os_nothread_mutex_unlock
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# define k5_once_t k5_os_nothread_once_t
|
|
Packit |
fd8b60 |
# define K5_ONCE_INIT K5_OS_NOTHREAD_ONCE_INIT
|
|
Packit |
fd8b60 |
# define k5_once k5_os_nothread_once
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#elif HAVE_PTHREAD
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# include <pthread.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Weak reference support, etc.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
Linux: Stub mutex routines exist, but pthread_once does not.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
Solaris <10: In libc there's a pthread_once that doesn't seem to do
|
|
Packit |
fd8b60 |
anything. Bleah. But pthread_mutexattr_setrobust_np is defined
|
|
Packit |
fd8b60 |
only in libpthread. However, some version of GNU libc (Red Hat's
|
|
Packit |
fd8b60 |
Fedora Core 5, reportedly) seems to have that function, but no
|
|
Packit |
fd8b60 |
declaration, so we'd have to declare it in order to test for its
|
|
Packit |
fd8b60 |
address. We now have tests to see if pthread_once actually works,
|
|
Packit |
fd8b60 |
so stick with that for now.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
Solaris 10: The real thread support now lives in libc, and
|
|
Packit |
fd8b60 |
libpthread is just a filter object. So we might as well use the
|
|
Packit |
fd8b60 |
real functions unconditionally. Since we haven't got a test for
|
|
Packit |
fd8b60 |
this property yet, we use NO_WEAK_PTHREADS defined in aclocal.m4
|
|
Packit |
fd8b60 |
depending on the OS type.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
IRIX 6.5 stub pthread support in libc is really annoying. The
|
|
Packit |
fd8b60 |
pthread_mutex_lock function returns ENOSYS for a program not linked
|
|
Packit |
fd8b60 |
against -lpthread. No link-time failure, no weak symbols, etc.
|
|
Packit |
fd8b60 |
The C library doesn't provide pthread_once; we can use weak
|
|
Packit |
fd8b60 |
reference support for that.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
If weak references are not available, then for now, we assume that
|
|
Packit |
fd8b60 |
the pthread support routines will always be available -- either the
|
|
Packit |
fd8b60 |
real thing, or functional stubs that merely prohibit creating
|
|
Packit |
fd8b60 |
threads.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
If we find a platform with non-functional stubs and no weak
|
|
Packit |
fd8b60 |
references, we may have to resort to some hack like dlsym on the
|
|
Packit |
fd8b60 |
symbol tables of the current process. */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#if defined(HAVE_PRAGMA_WEAK_REF) && !defined(NO_WEAK_PTHREADS)
|
|
Packit |
fd8b60 |
# define USE_CONDITIONAL_PTHREADS
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifdef USE_CONDITIONAL_PTHREADS
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Can't rely on useful stubs -- see above regarding Solaris. */
|
|
Packit |
fd8b60 |
typedef struct {
|
|
Packit |
fd8b60 |
pthread_once_t o;
|
|
Packit |
fd8b60 |
k5_os_nothread_once_t n;
|
|
Packit |
fd8b60 |
} k5_once_t;
|
|
Packit |
fd8b60 |
# define K5_ONCE_INIT { PTHREAD_ONCE_INIT, K5_OS_NOTHREAD_ONCE_INIT }
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
int k5_once(k5_once_t *once, void (*fn)(void));
|
|
Packit |
fd8b60 |
#else
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* no pragma weak support */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
typedef pthread_once_t k5_once_t;
|
|
Packit |
fd8b60 |
# define K5_ONCE_INIT PTHREAD_ONCE_INIT
|
|
Packit |
fd8b60 |
# define k5_once pthread_once
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#if defined(__mips) && defined(__sgi) && (defined(_SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__))
|
|
Packit |
fd8b60 |
# ifndef HAVE_PRAGMA_WEAK_REF
|
|
Packit |
fd8b60 |
# if defined(__GNUC__) && __GNUC__ < 3
|
|
Packit |
fd8b60 |
# error "Please update to a newer gcc with weak symbol support, or switch to native cc, reconfigure and recompile."
|
|
Packit |
fd8b60 |
# else
|
|
Packit |
fd8b60 |
# error "Weak reference support is required"
|
|
Packit |
fd8b60 |
# endif
|
|
Packit |
fd8b60 |
# endif
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
typedef pthread_mutex_t k5_os_mutex;
|
|
Packit |
fd8b60 |
# define K5_OS_MUTEX_PARTIAL_INITIALIZER \
|
|
Packit |
fd8b60 |
PTHREAD_MUTEX_INITIALIZER
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifdef USE_CONDITIONAL_PTHREADS
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# define k5_os_mutex_finish_init(M) (0)
|
|
Packit |
fd8b60 |
int k5_os_mutex_init(k5_os_mutex *m);
|
|
Packit |
fd8b60 |
int k5_os_mutex_destroy(k5_os_mutex *m);
|
|
Packit |
fd8b60 |
int k5_os_mutex_lock(k5_os_mutex *m);
|
|
Packit |
fd8b60 |
int k5_os_mutex_unlock(k5_os_mutex *m);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#else
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static inline int k5_os_mutex_finish_init(k5_os_mutex *m) { return 0; }
|
|
Packit |
fd8b60 |
# define k5_os_mutex_init(M) pthread_mutex_init((M), 0)
|
|
Packit |
fd8b60 |
# define k5_os_mutex_destroy(M) pthread_mutex_destroy((M))
|
|
Packit |
fd8b60 |
# define k5_os_mutex_lock(M) pthread_mutex_lock(M)
|
|
Packit |
fd8b60 |
# define k5_os_mutex_unlock(M) pthread_mutex_unlock(M)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#endif /* is pthreads always available? */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#elif defined _WIN32
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# define k5_once_t k5_os_nothread_once_t
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
typedef struct {
|
|
Packit |
fd8b60 |
HANDLE h;
|
|
Packit |
fd8b60 |
int is_locked;
|
|
Packit |
fd8b60 |
} k5_os_mutex;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# define K5_OS_MUTEX_PARTIAL_INITIALIZER { INVALID_HANDLE_VALUE, 0 }
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# define k5_os_mutex_finish_init(M) \
|
|
Packit |
fd8b60 |
(assert((M)->h == INVALID_HANDLE_VALUE), \
|
|
Packit |
fd8b60 |
((M)->h = CreateMutex(NULL, FALSE, NULL)) ? 0 : GetLastError())
|
|
Packit |
fd8b60 |
# define k5_os_mutex_init(M) \
|
|
Packit |
fd8b60 |
((M)->is_locked = 0, \
|
|
Packit |
fd8b60 |
((M)->h = CreateMutex(NULL, FALSE, NULL)) ? 0 : GetLastError())
|
|
Packit |
fd8b60 |
# define k5_os_mutex_destroy(M) \
|
|
Packit |
fd8b60 |
(CloseHandle((M)->h) ? ((M)->h = 0, 0) : GetLastError())
|
|
Packit |
fd8b60 |
# define k5_os_mutex_lock k5_win_mutex_lock
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static inline int k5_win_mutex_lock(k5_os_mutex *m)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
DWORD res;
|
|
Packit |
fd8b60 |
res = WaitForSingleObject(m->h, INFINITE);
|
|
Packit |
fd8b60 |
if (res == WAIT_FAILED)
|
|
Packit |
fd8b60 |
return GetLastError();
|
|
Packit |
fd8b60 |
/* Eventually these should be turned into some reasonable error
|
|
Packit |
fd8b60 |
code. */
|
|
Packit |
fd8b60 |
assert(res != WAIT_TIMEOUT);
|
|
Packit |
fd8b60 |
assert(res != WAIT_ABANDONED);
|
|
Packit |
fd8b60 |
assert(res == WAIT_OBJECT_0);
|
|
Packit |
fd8b60 |
/* Avoid locking twice. */
|
|
Packit |
fd8b60 |
assert(m->is_locked == 0);
|
|
Packit |
fd8b60 |
m->is_locked = 1;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# define k5_os_mutex_unlock(M) \
|
|
Packit |
fd8b60 |
(assert((M)->is_locked == 1), \
|
|
Packit |
fd8b60 |
(M)->is_locked = 0, \
|
|
Packit |
fd8b60 |
ReleaseMutex((M)->h) ? 0 : GetLastError())
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#else
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
# error "Thread support enabled, but thread system unknown"
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
typedef k5_os_mutex k5_mutex_t;
|
|
Packit |
fd8b60 |
#define K5_MUTEX_PARTIAL_INITIALIZER K5_OS_MUTEX_PARTIAL_INITIALIZER
|
|
Packit |
fd8b60 |
static inline int k5_mutex_init(k5_mutex_t *m)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
return k5_os_mutex_init(m);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
static inline int k5_mutex_finish_init(k5_mutex_t *m)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
return k5_os_mutex_finish_init(m);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
#define k5_mutex_destroy(M) \
|
|
Packit |
fd8b60 |
(k5_os_mutex_destroy(M))
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static inline void k5_mutex_lock(k5_mutex_t *m)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
int r = k5_os_mutex_lock(m);
|
|
Packit |
fd8b60 |
#ifndef NDEBUG
|
|
Packit |
fd8b60 |
if (r != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "k5_mutex_lock: Received error %d (%s)\n",
|
|
Packit |
fd8b60 |
r, strerror(r));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
assert(r == 0);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static inline void k5_mutex_unlock(k5_mutex_t *m)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
int r = k5_os_mutex_unlock(m);
|
|
Packit |
fd8b60 |
#ifndef NDEBUG
|
|
Packit |
fd8b60 |
if (r != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "k5_mutex_unlock: Received error %d (%s)\n",
|
|
Packit |
fd8b60 |
r, strerror(r));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
assert(r == 0);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#define k5_mutex_assert_locked(M) ((void)(M))
|
|
Packit |
fd8b60 |
#define k5_mutex_assert_unlocked(M) ((void)(M))
|
|
Packit |
fd8b60 |
#define k5_assert_locked k5_mutex_assert_locked
|
|
Packit |
fd8b60 |
#define k5_assert_unlocked k5_mutex_assert_unlocked
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Thread-specific data; implemented in a support file, because we'll
|
|
Packit |
fd8b60 |
need to keep track of some global data for cleanup purposes.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
Note that the callback function type is such that the C library
|
|
Packit |
fd8b60 |
routine free() is a valid callback. */
|
|
Packit |
fd8b60 |
typedef enum {
|
|
Packit |
fd8b60 |
K5_KEY_COM_ERR,
|
|
Packit |
fd8b60 |
K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME,
|
|
Packit |
fd8b60 |
K5_KEY_GSS_KRB5_CCACHE_NAME,
|
|
Packit |
fd8b60 |
K5_KEY_GSS_KRB5_ERROR_MESSAGE,
|
|
Packit |
fd8b60 |
K5_KEY_GSS_SPNEGO_STATUS,
|
|
Packit |
fd8b60 |
#if defined(__MACH__) && defined(__APPLE__)
|
|
Packit |
fd8b60 |
K5_KEY_IPC_CONNECTION_INFO,
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
K5_KEY_MAX
|
|
Packit |
fd8b60 |
} k5_key_t;
|
|
Packit |
fd8b60 |
/* rename shorthand symbols for export */
|
|
Packit |
fd8b60 |
#define k5_key_register krb5int_key_register
|
|
Packit |
fd8b60 |
#define k5_getspecific krb5int_getspecific
|
|
Packit |
fd8b60 |
#define k5_setspecific krb5int_setspecific
|
|
Packit |
fd8b60 |
#define k5_key_delete krb5int_key_delete
|
|
Packit |
fd8b60 |
extern int k5_key_register(k5_key_t, void (*)(void *));
|
|
Packit |
fd8b60 |
extern void *k5_getspecific(k5_key_t);
|
|
Packit |
fd8b60 |
extern int k5_setspecific(k5_key_t, void *);
|
|
Packit |
fd8b60 |
extern int k5_key_delete(k5_key_t);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
extern int KRB5_CALLCONV krb5int_mutex_alloc (k5_mutex_t **);
|
|
Packit |
fd8b60 |
extern void KRB5_CALLCONV krb5int_mutex_free (k5_mutex_t *);
|
|
Packit |
fd8b60 |
extern void KRB5_CALLCONV krb5int_mutex_lock (k5_mutex_t *);
|
|
Packit |
fd8b60 |
extern void KRB5_CALLCONV krb5int_mutex_unlock (k5_mutex_t *);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* In time, many of the definitions above should move into the support
|
|
Packit |
fd8b60 |
library, and this file should be greatly simplified. For type
|
|
Packit |
fd8b60 |
definitions, that'll take some work, since other data structures
|
|
Packit |
fd8b60 |
incorporate mutexes directly, and our mutex type is dependent on
|
|
Packit |
fd8b60 |
configuration options and system attributes. For most functions,
|
|
Packit |
fd8b60 |
though, it should be relatively easy.
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
For now, plugins should use the exported functions, and not the
|
|
Packit |
fd8b60 |
above macros, and use krb5int_mutex_alloc for allocations. */
|
|
Packit |
fd8b60 |
#if defined(PLUGIN) || (defined(CONFIG_SMALL) && !defined(THREAD_SUPPORT_IMPL))
|
|
Packit |
fd8b60 |
#undef k5_mutex_lock
|
|
Packit |
fd8b60 |
#define k5_mutex_lock krb5int_mutex_lock
|
|
Packit |
fd8b60 |
#undef k5_mutex_unlock
|
|
Packit |
fd8b60 |
#define k5_mutex_unlock krb5int_mutex_unlock
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#endif /* multiple inclusion? */
|