2004-04-24 Ken Raeburn <raeburn@mit.edu>
* aclocal.m4 (KRB5_BUILD_LIBRARY_WITH_DEPS): Look for perl.
+ (KRB5_AC_PRAGMA_WEAK_REF): New macro, tests support for weak
+ references using "#pragma weak".
+ (CONFIG_RULES): Invoke it.
+ (KRB5_AC_ENABLE_THREADS): Test enableval, not withval. If
+ ACX_PTHREAD can't determine thread support options and thread
+ support was requested, report an error. Display the options
+ selected by ACX_PTHREAD. Test for pthread_once without pthread
+ options, and pthread_mutexattr_setrobust_np both with and without
+ pthread options.
+ (KRB5_AC_GCC_ATTRS): New macro, dummy for now.
2004-04-22 Ken Raeburn <raeburn@mit.edu>
libobj_frag=$srcdir/$ac_config_fragdir/libobj.in
AC_SUBST_FILE(libobj_frag)
dnl
-KRB5_AC_ENABLE_THREADS dnl
+KRB5_AC_PRAGMA_WEAK_REF
+KRB5_AC_ENABLE_THREADS
])dnl
dnl Maintainer mode, akin to what automake provides, 'cept we don't
AC_DEFUN([KRB5_AC_ENABLE_THREADS],[
AC_ARG_ENABLE([thread-support],
AC_HELP_STRING([--enable-thread-support],use PRELIMINARY EXPERIMENTAL UNFINISHED POSIX-only thread support @<:@disabled@:>@),
-[ if test "$withval" = yes ; then
+[ if test "$enableval" = yes ; then
AC_MSG_NOTICE(enabling PRELIMINARY EXPERIMENTAL UNFINISHED POSIX-only thread support)
AC_DEFINE(ENABLE_THREADS,1,[Define if thread support enabled])
fi
])
dnl Maybe this should be inside the conditional above? Doesn't cache....
-ACX_PTHREAD
+if test "$enable_thread_support" = yes; then
+ACX_PTHREAD(,[AC_MSG_ERROR([cannot determine options for enabling thread support])])
+AC_MSG_NOTICE(PTHREAD_CC = $PTHREAD_CC)
+AC_MSG_NOTICE(PTHREAD_CFLAGS = $PTHREAD_CFLAGS)
+AC_MSG_NOTICE(PTHREAD_LIBS = $PTHREAD_LIBS)
dnl Not really needed -- if pthread.h isn't found, ACX_PTHREAD will fail.
AC_CHECK_HEADERS(pthread.h)
+fi
+dnl We want to know where these routines live, so on systems with weak
+dnl reference support we can figure out whether or not the pthread library
+dnl has been linked in.
+dnl If we don't add any libraries for thread support, don't bother.
+AC_CHECK_FUNCS(pthread_once pthread_mutexattr_setrobust_np)
+old_CC="$CC"
+test "$PTHREAD_CC" != "" && CC=$PTHREAD_CC
+old_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+old_LIBS="$LIBS"
+LIBS="$PTHREAD_LIBS $LIBS"
+AC_MSG_NOTICE(rechecking with PTHREAD_... options)
+AC_CHECK_LIB(c, pthread_mutexattr_setrobust_np,
+ [AC_DEFINE(HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP_IN_THREAD_LIB,1,[Define if pthread_mutexattr_setrobust_np is provided in the thread library.])])
])
+LIBS="$old_LIBS"
+CC="$old_CC"
+fi
dnl This is somewhat gross and should go away when the build system
dnl is revamped. -- tlyu
AC_REQUIRE([AC_PROG_ARCHIVE_ADD])dnl
AC_REQUIRE([AC_PROG_INSTALL])dnl
AC_CHECK_PROG(AR, ar, ar, false)
-AC_CHECK_PROG(PERL, perl, false)
+AC_CHECK_PROG(PERL, perl, perl, false)
AC_SUBST(LIBLIST)
AC_SUBST(LIBLINKS)
AC_SUBST(MAKE_SHLIB_COMMAND)
AC_SUBST(PRIOCNTL_HACK)])
dnl
dnl
+dnl KRB5_AC_GCC_ATTRS
+AC_DEFUN([KRB5_AC_GCC_ATTRS],
+[
+])
+dnl
+dnl
+dnl KRB5_AC_PRAGMA_WEAK_REF
+AC_DEFUN([KRB5_AC_PRAGMA_WEAK_REF],
+[AC_CACHE_CHECK([whether pragma weak references are supported],
+krb5_cv_pragma_weak_ref,
+[AC_TRY_LINK([#pragma weak flurbl
+extern int flurbl(void);],[if (&flurbl != 0) return 1;],
+krb5_cv_pragma_weak_ref=yes,krb5_cv_pragma_weak_ref=no)])
+if test $krb5_cv_pragma_weak_ref = yes ; then
+ AC_DEFINE(HAVE_PRAGMA_WEAK_REF,1,[Define if #pragma weak references work])
+fi])
+dnl
+dnl
m4_include(config/ac-archive/acx_pthread.m4)
+2004-04-24 Ken Raeburn <raeburn@mit.edu>
+
+ * k5-platform.h (DELAY_INITIALIZER): New macro, defined always.
+ (CONSTRUCTOR_ATTR_WORKS, DESTRUCTOR_ATTR_WORKS): New macro,
+ defined for Linux and NetBSD, and Solaris with gcc.
+ (USE_LINKER_FINI_OPTION): New macro, defined on IRIX, and on
+ Solaris with native compiler.
+ (JOIN2, JOIN2_2, JOIN3, JOIN3_2, JOIN4, JOIN4_2): New utility
+ macros.
+ (k5_init_t): New typedef, for some platforms.
+ (MAKE_INIT_FUNCTION, MAKE_FINI_FUNCTION, CALL_INIT_FUNCTION,
+ INITIALIZER_RAN, PROGRAM_EXITING): New macros for library
+ initialization and finalization support.
+
+ * k5-thread.h: Use k5_mutex_init instead of K5_MUTEX_INITIALIZER
+ for multiple-inclusion protection.
+ (K5_MUTEX_DEBUG_INITIALIZER): Change initial initialized flag to
+ 2.
+ (k5_mutex_debug_finish_init): New macro, verifies value 2 and
+ changes it to 1.
+ (k5_mutex_debug_lock): Test various values of initialized and
+ locked flags separately, so assertion failure message is more
+ immediately informative.
+ (K5_MUTEX_PARTIAL_INITIALIZER): Rename from K5_MUTEX_INITIALIZER.
+ (k5_mutex_finish_init): New macro.
+ (pthread_once, pthread_mutexattr_setrobust_np): Consider
+ declaring weak based on availability.
+ (K5_PTHREADS_LOADED): New macro, tests to see if pthread
+ functions are available, if weak references are supported.
+ (k5_mutex_lock, k5_mutex_unlock): On IRIX, redefine to bypass
+ pthread code if pthread library isn't loaded.
+ (k5_once_t): New typedef.
+ (K5_ONCE_INIT, k5_once): New macros.
+
+ * Makefile.in (autoconf.stmp): Depend on aclocal.m4.
+
+ * k5-platform.h: Include limits.h before testing for SIZE_MAX.
+
+ * k5-thread.h (k5_key_t): New enumerator typedef.
+ (k5_key_register, k5_getspecific, k5_setspecific): New macros.
+ (krb5int_key_register, krb5int_getspecific, krb5int_setspecific,
+ krb5int_key_delete): Declare.
+
2004-04-16 Sam Hartman <hartmans@mit.edu>
* k5-int.h: krb5int_populate_gic_opt now takes credentials so it
krb5/autoconf.h: $(srcdir)/krb5/autoconf.h.in
(cd krb5; $(MAKE) autoconf.h)
$(srcdir)/krb5/autoconf.h.in: @MAINT@ $(srcdir)/krb5/autoconf.stmp
-$(srcdir)/krb5/autoconf.stmp: $(srcdir)/configure.in
+$(srcdir)/krb5/autoconf.stmp: $(srcdir)/configure.in $(SRCTOP)/aclocal.m4
cd $(srcdir) && ($(AUTOHEADER) --include=$(CONFIG_RELTOPDIR) $(AUTOHEADERFLAGS) || $(AUTOHEADER) --localdir=$(CONFIG_RELTOPDIR) $(AUTOHEADERFLAGS))
touch $(srcdir)/krb5/autoconf.stmp
* Some platform-dependent definitions to sync up the C support level.
* Some to a C99-ish level, some related utility code.
*
- * Currently: make "static inline" work; 64-bit types and load/store
- * code; SIZE_MAX.
+ * Currently:
+ * + make "static inline" work
+ * + 64-bit types and load/store code
+ * + SIZE_MAX
+ * + shared library init/fini hooks
*/
#ifndef K5_PLATFORM_H
#include "autoconf.h"
+
+/* Initialization and finalization function support for libraries.
+
+ At top level, before the functions are defined or even declared:
+ MAKE_INIT_FUNCTION(init_fn);
+ MAKE_FINI_FUNCTION(fini_fn);
+ int init_fn(void) { ... }
+ void fini_fn(void) { if (INITIALIZER_RAN(init_fn)) ... }
+
+ In code, in the same file:
+ err = CALL_INIT_FUNCTION(init_fn);
+
+ To trigger or verify the initializer invocation from another file,
+ an additional function must be created.
+
+ The init_fn and fini_fn names should be chosen such that any
+ exported names staring with those names, and optionally followed by
+ additional characters, fits in with any namespace constraints on
+ the library in question.
+
+
+ Implementation outline:
+
+ Windows: MAKE_FINI_FUNCTION creates a symbol with a magic name that
+ is sought at library build time, and code is added to invoke the
+ function when the library is unloaded. MAKE_INIT_FUNCTION does
+ likewise, but the function is invoked when the library is loaded,
+ and an extra variable is declared to hold an error code and a "yes
+ the initializer ran" flag. CALL_INIT_FUNCTION blows up if the flag
+ isn't set, otherwise returns the error code.
+
+ UNIX: MAKE_INIT_FUNCTION creates and initializes a variable with a
+ name derived from the function name, containing a k5_once_t
+ (pthread_once_t or int), an error code, and a pointer to the
+ function. The function itself is declared static, but the
+ associated variable has external linkage. CALL_INIT_FUNCTION
+ ensures thath the function is called exactly once (pthread_once or
+ just check the flag) and returns the stored error code (or the
+ pthread_once error).
+
+ UNIX, with compiler support: MAKE_FINI_FUNCTION declares the
+ function as a destructor, and the run time linker support or
+ whatever will cause it to be invoked when the library is unloaded,
+ the program ends, etc.
+
+ UNIX, with linker support: MAKE_FINI_FUNCTION creates a symbol with
+ a magic name that is sought at library build time, and linker
+ options are used to mark it as a finalization function for the
+ library. The symbol must be exported.
+
+ UNIX, no library finalization support: The finalization function
+ never runs, and we leak memory. Tough.
+
+
+
+ For maximum flexibility in defining the macros, the function name
+ parameter should be a simple name, not even a macro defined as
+ another name. The function should have a unique name, and should
+ conform to whatever namespace is used by the library in question.
+
+ If the macro expansion needs the function to have been declared, it
+ must include a declaration. If it is not necessary for the symbol
+ name to be exported from the object file, the macro should declare
+ it as "static". Hence the signature must exactly match "void
+ foo(void)". (ANSI C allows a static declaration followed by a
+ non-static one; the result is internal linkage.) The macro
+ expansion has to come before the function, because gcc apparently
+ won't act on "__attribute__((constructor))" if it comes after the
+ function definition.
+
+ This is going to be compiler- and environment-specific, and may
+ require some support at library build time, and/or "asm"
+ statements.
+
+ It's okay for this code to require that the library be built
+ with the same compiler and compiler options throughout, but
+ we shouldn't require that the library and application use the
+ same compiler.
+
+ For static libraries, we don't really care about cleanup too much,
+ since it's all memory handling and mutex allocation which will all
+ be cleaned up when the program exits. Thus, it's okay if gcc-built
+ static libraries don't play nicely with cc-built executables when
+ it comes to static constructors, just as long as it doesn't cause
+ linking to fail.
+
+ For dynamic libraries on UNIX, we'll use pthread_once-type support
+ to do delayed initialization, so if finalization can't be made to
+ work, we'll only have memory leaks in a load/use/unload cycle. If
+ anyone (like, say, the OS vendor) complains about this, they can
+ tell us how to get a shared library finalization function invoked
+ automatically. */
+
+#if !defined(_WIN32xxx)
+# define DELAY_INITIALIZER
+#endif
+
+/* These should be turned into feature tests or otherwise driven from
+ the configure script. */
+#if defined(__linux__) || defined(__NetBSD__) \
+ || (defined(__sun__) && defined(__svr4__) && defined(__GNUC__))
+# define CONSTRUCTOR_ATTR_WORKS
+# define DESTRUCTOR_ATTR_WORKS
+#endif
+#if defined(__sgi) && defined(__mips) && defined(_SYSTYPE_SVR4) /* IRIX? */
+# define USE_LINKER_FINI_OPTION
+#endif
+#if !defined(__GNUC__) && defined(__sun) && defined(__SVR4) && defined(__SUNPRO_C) /* Solaris ld -z finiarray */
+# define USE_LINKER_FINI_OPTION
+#endif
+
+# define JOIN4_2(A,B,C,D) A ## B ## C ## D
+# define JOIN4(A,B,C,D) JOIN4_2(A,B,C,D)
+# define JOIN3_2(A,B,C) A ## B ## C
+# define JOIN3(A,B,C) JOIN3_2(A,B,C)
+# define JOIN2_2(A,B) A ## B
+# define JOIN2(A,B) JOIN2_2(A,B)
+
+/* XXX Should test USE_LINKER_INIT_OPTION early, and if it's set,
+ always provide a function by the expected name, even if we're
+ delaying initialization. */
+
+#if defined(DELAY_INITIALIZER)
+
+/* Run the initialization code during program execution, at the latest
+ possible moment. This means multiple threads may be active. */
+# include "k5-thread.h"
+typedef struct { k5_once_t once; int error, did_run; void (*fn)(void); } k5_init_t;
+# define MAKE_INIT_FUNCTION(NAME) \
+ static int NAME(void); \
+ /* forward declaration for use in initializer */ \
+ static void JOIN2(NAME, __aux) (void); \
+ static k5_init_t JOIN2(NAME, __once) = \
+ { K5_ONCE_INIT, 0, 0, JOIN2(NAME, __aux) }; \
+ static void JOIN2(NAME, __aux) (void) \
+ { \
+ JOIN2(NAME, __once).did_run = 1; \
+ JOIN2(NAME, __once).error = NAME(); \
+ } \
+ /* so ';' following macro use won't get error */ \
+ static int NAME(void)
+# define CALL_INIT_FUNCTION(NAME) \
+ k5_call_init_function(& JOIN2(NAME, __once))
+static inline int k5_call_init_function(k5_init_t *i)
+{
+ int err;
+ err = k5_once(&i->once, i->fn);
+ if (err)
+ return err;
+ assert (i->did_run != 0);
+ return i->error;
+}
+/* This should be called in finalization only, so we shouldn't have
+ multiple active threads mucking around in our library at this
+ point. So ignore the once_t object and just look at the flag.
+
+ XXX Could we have problems with memory coherence between
+ processors if we don't invoke mutex/once routines? */
+# define INITIALIZER_RAN(NAME) \
+ (JOIN2(NAME, __once).did_run && JOIN2(NAME, __once).error == 0)
+
+# define PROGRAM_EXITING() (0)
+
+#elif defined(__GNUC__) && !defined(_WIN32) && defined(CONSTRUCTOR_ATTR_WORKS)
+
+/* Run initializer at load time, via GCC/C++ hook magic. */
+typedef struct { int error; unsigned char did_run; } k5_init_t;
+# define MAKE_INIT_FUNCTION(NAME) \
+ static k5_init_t JOIN2(NAME, __ran) \
+ = { 0, 2 }; \
+ static void JOIN2(NAME, __aux)(void) \
+ __attribute__((constructor)); \
+ static int NAME(void); \
+ static void JOIN2(NAME, __aux)(void) \
+ { \
+ JOIN2(NAME, __ran).error = NAME(); \
+ JOIN2(NAME, __ran).did_run = 3; \
+ } \
+ static int NAME(void)
+# define CALL_INIT_FUNCTION(NAME) \
+ (JOIN2(NAME, __ran).did_run == 3 \
+ ? JOIN2(NAME, __ran).error \
+ : (abort(),0))
+# define INITIALIZER_RAN(NAME) (JOIN2(NAME, __ran).error == 0)
+
+#elif defined(LINKER_HAS_INIT_OPTION)
+
+/* Run initializer at load time, via linker magic. */
+typedef struct { int error; unsigned char did_run; } k5_init_t;
+# define MAKE_INIT_FUNCTION(NAME) \
+ static k5_init_t JOIN2(NAME, __ran) \
+ = { 0, 2 }; \
+ static int NAME(void); \
+ void JOIN2(NAME, __aux) \
+ { \
+ JOIN2(NAME, __ran).error = NAME(); \
+ JOIN2(NAME, __ran).did_run = 3; \
+ } \
+ static int NAME(void)
+# define CALL_INIT_FUNCTION(NAME) \
+ (JOIN2(NAME, __ran).did_run == 3 \
+ ? JOIN2(NAME, __ran).error \
+ : (abort(),0))
+# define INITIALIZER_RAN(NAME) \
+ (JOIN2(NAME, __ran).error == 0)
+
+# define PROGRAM_EXITING() (0)
+
+#else
+
+# error "Don't know how to do load-time initializers for this configuration."
+
+# define PROGRAM_EXITING() (0)
+
+#endif
+
+
+
+#ifdef USE_LINKER_FINI_OPTION
+/* If we're told the linker option will be used, it doesn't really
+ matter what compiler we're using. Do it the same way
+ regardless. */
+
+# define MAKE_FINI_FUNCTION(NAME) \
+ void NAME(void)
+
+#elif defined(__GNUC__) && !defined(_WIN32) && defined(DESTRUCTOR_ATTR_WORKS)
+/* If we're using gcc, if the C++ support works, the compiler should
+ build executables and shared libraries that support the use of
+ static constructors and destructors. The C compiler supports a
+ function attribute that makes use of the same facility as C++.
+
+ XXX How do we know if the C++ support actually works? */
+# define MAKE_FINI_FUNCTION(NAME) \
+ static void NAME(void) __attribute__((destructor))
+
+#else
+
+# error "Don't know how to do unload-time finalization for this configuration."
+
+#endif
+
+
/* 64-bit support: krb5_ui_8 and krb5_int64.
This should move to krb5.h eventually, but without the namespace
# define UINT64_TYPE unsigned long long
#endif
+#include <limits.h>
#ifndef SIZE_MAX
# define SIZE_MAX ((size_t)((size_t)0 - 1))
#endif
* Preliminary thread support.
*/
-#ifndef K5_MUTEX_INITIALIZER /* handle multiple inclusion */
+#ifndef k5_mutex_init /* handle multiple inclusion */
#include "autoconf.h"
/* Interface (tentative):
- k5_mutex_t foo_mutex = K5_MUTEX_INITIALIZER;
+ Mutex support:
+
+ // Between these two, we should be able to do pure compile-time
+ // and pure run-time initialization.
+ // POSIX: partial initializer is PTHREAD_MUTEX_INITIALIZER,
+ // finish does nothing
+ // Windows: partial initializer is an invalid handle,
+ // finish does the real initialization work
+ // debug: partial initializer sets one magic value,
+ // finish verifies and sets a new magic value for
+ // lock/unlock to check
+ k5_mutex_t foo_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+ int k5_mutex_finish_init(k5_mutex_t *);
+ // for dynamic allocation
int k5_mutex_init(k5_mutex_t *);
+ // Must work for both kinds of alloc, even if it means adding flags.
int k5_mutex_destroy(k5_mutex_t *);
+
+ // As before.
int k5_mutex_lock(k5_mutex_t *);
int k5_mutex_unlock(k5_mutex_t *);
- k5_key_t key;
- int k5_key_create(k5_key_t *, void (*destructor)(void *));
+
+ 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
+ function (see below). On Windows, it would be called at library
+ load time. These functions, or functions they calls, should be the
+ only places that k5_mutex_finish_init gets called.
+
+ A second function or macro called at various possible "first" entry
+ points which either calls pthread_once on the first function
+ (POSIX), or checks some flag set by the first function (Windows,
+ debug support), and possibly returns an error. (In the
+ non-threaded case, a simple flag can be used to avoid multiple
+ invocations, and the mutexes don't need run-time initialization
+ anyways.)
+
+ A third function for library termination calls mutex_destroy on
+ each mutex for the library. This function would be called
+ automatically at library unload time. If it turns out to be needed
+ at exit time for libraries that don't get unloaded, perhaps we
+ 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:
+
+ k5_once_t foo_once = K5_ONCE_INIT;
+ k5_once(k5_once_t *, void (*)(void));
+
+ For POSIX: Map onto pthread_once facility.
+ For non-threaded case: A simple flag.
+ For Windows: Not needed; library init code takes care of it.
+
+
+ Thread-specific data:
+
+ // TSD keys are limited in number in gssapi/krb5/com_err; enumerate
+ // them all. This allows support code init to allocate the
+ // necessary storage for pointers all at once, and avoids any
+ // possible error in key creation.
+ enum { ... } k5_key_t;
+ // Register destructor function. Called in library init code.
+ int k5_key_register(k5_key_t, void (*destructor)(void *));
+ // Returns NULL or data.
void *k5_getspecific(k5_key_t);
- int k5_setspecific(k5_key_t, const void *);
- ... stuff to signal library termination ...
+ // Returns error if key out of bounds, or the pointer table can't
+ // be allocated. A call to k5_key_register must have happened first.
+ // This may trigger the calling of pthread_setspecific on POSIX.
+ int k5_setspecific(k5_key_t, void *);
+ // Called in library termination code.
+ // Trashes data in all threads, calling the registered destructor
+ // (but calling it from the current thread).
+ int k5_key_delete(k5_key_t);
+
+ For the non-threaded version, the support code will have a static
+ array indexed by k5_key_t values, and get/setspecific simply access
+ the array elements.
+
+ The TSD destructor table is global state, protected by a mutex if
+ threads are enabled.
+
+ Debug support: Not much. Might check if k5_key_register has been
+ called and abort if not.
+
+
+ Any actual external symbols will use the krb5int_ prefix. The k5_
+ names will be simple macros or inline functions to rename the
+ external symbols, or slightly more complex ones to expand the
+ implementation inline (e.g., map to POSIX versions and/or debug
+ code using __FILE__ and the like).
- More to be added, probably. */
+
+ More to be added, perhaps. */
#ifndef HAVE_PTHREAD_H
# undef ENABLE_THREADS
short lineno;
const char *filename;
} k5_mutex_debug_info;
-#define K5_MUTEX_DEBUG_INITIALIZER { 1, K5_MUTEX_DEBUG_UNLOCKED, 0, 0 }
+#define K5_MUTEX_DEBUG_INITIALIZER { 2, K5_MUTEX_DEBUG_UNLOCKED, 0, 0 }
#define K5_MUTEX_DEBUG_LOCKED 4
#define K5_MUTEX_DEBUG_UNLOCKED 3
+#define k5_mutex_debug_finish_init(M) \
+ (assert((M)->initialized == 2), (M)->initialized = 1, 0)
#define k5_mutex_debug_init(M) \
((M)->initialized = 1, \
(M)->locked = K5_MUTEX_DEBUG_UNLOCKED, \
&& (M)->locked == K5_MUTEX_DEBUG_UNLOCKED), \
(M)->initialized = 0)
#define k5_mutex_debug_lock(M) \
- (assert((M)->initialized == 1 \
- && (M)->locked == K5_MUTEX_DEBUG_UNLOCKED), \
+ (assert((M)->initialized != 2), \
+ assert((M)->initialized != 0), \
+ assert((M)->initialized == 1), \
+ assert((M)->locked != 0), \
+ assert((M)->locked != K5_MUTEX_DEBUG_LOCKED), \
+ assert((M)->locked == K5_MUTEX_DEBUG_UNLOCKED), \
(M)->locked = K5_MUTEX_DEBUG_LOCKED, \
(M)->lineno = __LINE__, (M)->filename = __FILE__, 0)
#define k5_mutex_debug_unlock(M) \
(M)->locked = K5_MUTEX_DEBUG_UNLOCKED, \
(M)->lineno = __LINE__, (M)->filename = __FILE__, 0)
+
+typedef enum {
+ K5_KEY_COM_ERR,
+ K5_KEY_MAX
+} k5_key_t;
+
+
#ifdef ENABLE_THREADS
#include <pthread.h>
#ifndef DEBUG_THREADS
typedef pthread_mutex_t k5_mutex_t;
-#define K5_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#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)
k5_mutex_debug_info debug;
pthread_mutex_t lock;
} k5_mutex_t;
-#define K5_MUTEX_INITIALIZER { K5_MUTEX_DEBUG_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }
+#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))
+ assert(0==pthread_mutex_destroy(&(M)->lock)))
#define k5_mutex_lock(M) (k5_mutex_debug_lock(&(M)->debug), \
assert(0==pthread_mutex_lock(&(M)->lock)), \
0)
assert(0==pthread_mutex_unlock(&(M)->lock)), \
0)
+#if defined(__mips) && defined(__sgi) && 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.
+
+ The C library doesn't provide pthread_once; we can use weak
+ reference support for that. */
+#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
+
#endif /* DEBUG_THREADS ? */
-#if 0
-/* *** This will need to change.
- We'd prefer to use only one POSIX data key.
-
- And we need to do some additional bookkeeping for dealing with
- unloading libraries (free storage, destroy the key), such that we
- can't just map the functions to POSIX in the long term. */
-typedef pthread_key_t k5_key_t;
-#define k5_key_create(K,D) pthread_key_create(K,D)
-#define k5_getspecific(K) pthread_getspecific(K)
-#define k5_setspecific(K,P) pthread_setspecific(K,P)
+/* Linux with weak reference support:
+ 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.
+ */
+
+#ifdef HAVE_PRAGMA_WEAK_REF
+# pragma weak pthread_once
+# ifdef HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP_IN_THREAD_LIB
+# pragma weak pthread_mutexattr_setrobust_np
+# endif
+# if !defined HAVE_PTHREAD_ONCE
+# define K5_PTHREADS_LOADED (&pthread_once != 0)
+# elif !defined HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP \
+ && defined HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP_IN_THREAD_LIB
+# define K5_PTHREADS_LOADED (&pthread_mutexattr_setrobust_np != 0)
+# else
+# define K5_PTHREADS_LOADED (1)
+# endif
+#else
+/* no pragma weak support */
+# define K5_PTHREADS_LOADED (1)
+#endif
+
+/* Would be nice to use a union, but we need to initialize both. */
+#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)
+#else
+typedef pthread_once_t k5_once_t;
+#define K5_ONCE_INIT PTHREAD_ONCE_INIT
+#define k5_once pthread_once
#endif
#else /* ! ENABLE_THREADS */
we're pairing up lock and unlock calls properly. */
#define k5_mutex_t k5_mutex_debug_info
-#define K5_MUTEX_INITIALIZER K5_MUTEX_DEBUG_INITIALIZER
+#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_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 */
/* no-op versions */
typedef char k5_mutex_t;
-#define K5_MUTEX_INITIALIZER 0
+#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_once_t unsigned char
+#define K5_ONCE_INIT 2
+#define k5_once(F,O) \
+ (*(O) == 3 ? 0 : ((F)(), *(O) = 3, 0))
+
#endif /* DEBUG_THREADS ? */
#endif /* ENABLE_THREADS ? */
-#endif /* K5_MUTEX_INITIALIZER for multiple inclusion */
+/* rename shorthand symbols for export */
+#define k5_key_register krb5int_key_register
+#define k5_getspecific krb5int_getspecific
+#define k5_setspecific krb5int_setspecific
+#define k5_key_delete krb5int_key_delete
+extern int k5_key_register(k5_key_t, void (*)(void *));
+extern void *k5_getspecific(k5_key_t);
+extern int k5_setspecific(k5_key_t, void *);
+extern int k5_key_delete(k5_key_t);
+
+#endif /* multiple inclusion? */
+2004-04-24 Ken Raeburn <raeburn@mit.edu>
+
+ * gss_libinit.c: Include k5-platform.h.
+ (gssint_lib_init, gssint_lib_fini): New init/fini functions.
+ Create and clean up the mutex in kg_vdb.
+ (gssint_initialize_library): Verify the library initializer has
+ run successfully.
+
2004-04-22 Ken Raeburn <raeburn@mit.edu>
* libgssapi_krb5.exports: New file.
+2004-04-24 Ken Raeburn <raeburn@mit.edu>
+
+ * gssapiP_generic.h (G_SET_INIT): Use the new mutex partial
+ initializer now.
+
2004-03-14 Ken Raeburn <raeburn@mit.edu>
* gssapiP_generic.h (struct _g_set_elt, g_set_elt): Renamed from
k5_mutex_t mutex;
void *data;
} g_set;
-#define G_SET_INIT { K5_MUTEX_INITIALIZER, 0 }
+#define G_SET_INIT { K5_MUTEX_PARTIAL_INITIALIZER, 0 }
int g_set_init (g_set_elt *s);
int g_set_destroy (g_set_elt *s);
#include "gssapiP_krb5.h"
#include "gss_libinit.h"
+#include "k5-platform.h"
static int initialized = 0;
* Initialize the GSSAPI library.
*/
+MAKE_INIT_FUNCTION(gssint_lib_init);
+MAKE_FINI_FUNCTION(gssint_lib_fini);
+
+int gssint_lib_init(void)
+{
+ return k5_mutex_finish_init(&kg_vdb.mutex);
+}
+
+void gssint_lib_fini(void)
+{
+ if (!INITIALIZER_RAN(gssint_lib_init) || PROGRAM_EXITING())
+ return;
+ k5_mutex_destroy(&kg_vdb.mutex);
+}
+
OM_uint32 gssint_initialize_library (void)
{
-
if (!initialized) {
#if !USE_BUNDLE_ERROR_STRINGS
add_error_table(&et_k5g_error_table);
add_error_table(&et_ggss_error_table);
#endif
- initialized = 1;
+ initialized = 1;
}
-
- return 0;
+
+ return CALL_INIT_FUNCTION(gssint_lib_init);
}
/*
void gssint_cleanup_library (void)
{
-
assert (initialized);
-
+
#if !USE_BUNDLE_ERROR_STRINGS
remove_error_table(&et_k5g_error_table);
remove_error_table(&et_ggss_error_table);
#endif
-
+
initialized = 0;
}
(kg_set_ccache_name): Likewise. Return after an error rather
than continuing.
+ * krb5_gss_glue.c (gss_import_name): Call
+ gssint_initialize_library and check the return status.
+
2004-04-13 Jeffrey Altman <jaltman@mit.edu>
* k5unseal.c: gss_krb5int_unseal_token_v3() takes a pointer to
gss_OID input_name_type;
gss_name_t *output_name;
{
- return(krb5_gss_import_name(minor_status, input_name_buffer,
- input_name_type, output_name));
+ OM_uint32 err;
+ err = gssint_initialize_library();
+ if (err) {
+ *minor_status = err;
+ return GSS_S_FAILURE;
+ }
+ return(krb5_gss_import_name(minor_status, input_name_buffer,
+ input_name_type, output_name));
}
/* V2 */
+2004-04-24 Ken Raeburn <raeburn@mit.edu>
+
+ * krb5_libinit.c: Include k5-platform.h.
+ (krb5int_lib_init, krb5int_lib_fini): New init/fini functions.
+ Call the corresponding functions for the ccache, keytab, and
+ rcache code. Incorporate the finalization code from
+ krb5int_cleanup_library.
+ (krb5int_initialize_library): Make sure the init function runs
+ successfully.
+ (krb5int_cleanup_library): Now empty.
+
2004-04-22 Ken Raeburn <raeburn@mit.edu>
* libkrb5.exports: New file.
+2004-04-24 Ken Raeburn <raeburn@mit.edu>
+
+ * ccbase.c: Include ctype.h.
+ (cc_typelist_lock): Use the new partial initializer.
+ (krb5int_cc_initialize): New function; finish the initialization.
+ (krb5int_cc_finalize): New function; destroy the mutex and free
+ any storage for registered types.
+
2004-04-13 Jeffrey Altman <jaltman@mit.edu>
* ccbase.c:
&cc_mcc_entry };
static struct krb5_cc_typelist *cc_typehead = &cc_fcc_entry;
-static k5_mutex_t cc_typelist_lock = K5_MUTEX_INITIALIZER;
+static k5_mutex_t cc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+int
+krb5int_cc_initialize(void)
+{
+ return k5_mutex_finish_init(&cc_typelist_lock);
+}
+
+void
+krb5int_cc_finalize(void)
+{
+ struct krb5_cc_typelist *t, *t_next;
+ k5_mutex_destroy(&cc_typelist_lock);
+ for (t = cc_typehead; t != &cc_fcc_entry; t = t_next) {
+ t_next = t->next;
+ free(t);
+ }
+}
/*
* particular cache type.
*/
+#include <ctype.h>
krb5_error_code KRB5_CALLCONV
krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache)
{
+2004-04-24 Ken Raeburn <raeburn@mit.edu>
+
+ * ktbase.c: Include ctype.h.
+ (k5_typehead_lock): Use new partial initializer.
+ (krb5int_kt_initialize): New function; finish mutex
+ initialization.
+ (krb5int_kt_finalize): New function; destroy the mutex and free
+ storage associated with registered types.
+
2004-04-13 Jeffrey Altman <jaltman@mit.edu>
* ktbase.c:
};
static const struct krb5_kt_typelist *kt_typehead = &krb5_kt_typelist_srvtab;
/* Lock for protecting the type list. */
-static k5_mutex_t kt_typehead_lock = K5_MUTEX_INITIALIZER;
+static k5_mutex_t kt_typehead_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+int krb5int_kt_initialize(void)
+{
+ return k5_mutex_finish_init(&kt_typehead_lock);
+}
+
+void
+krb5int_kt_finalize(void)
+{
+ struct krb5_kt_typelist *t, *t_next;
+ k5_mutex_destroy(&kt_typehead_lock);
+ for (t = kt_typehead; t != &krb5_kt_typelist_srvtab; t = t_next) {
+ t_next = t->next;
+ free(t);
+ }
+}
/*
* particular keytab type.
*/
+#include <ctype.h>
krb5_error_code KRB5_CALLCONV
krb5_kt_resolve (krb5_context context, const char *name, krb5_keytab *ktid)
{
-2004-04-16 Sam Hartman <hartmans@mit.edu>
+2004-04-24 Ken Raeburn <raeburn@mit.edu>
+
+ * init_ctx.c (init_common): In UNIX case, check the return value
+ from krb5int_initialize_library.
+2004-04-16 Sam Hartman <hartmans@mit.edu>
- * gic_pwd.c (krb5int_populate_gic_opt): Take credentials and populate lifetime options based on them.
+ * gic_pwd.c (krb5int_populate_gic_opt): Take credentials and
+ populate lifetime options based on them.
* gic_keytab.c gic_pwd.c : update callers
if (retval)
return retval;
#else /* assume UNIX for now */
- krb5int_initialize_library ();
+ retval = krb5int_initialize_library ();
+ if (retval)
+ return retval;
#endif
*context = 0;
#endif
#include "krb5_libinit.h"
+#include "k5-platform.h"
static int initialized = 0;
* Initialize the Kerberos v5 library.
*/
+MAKE_INIT_FUNCTION(krb5int_lib_init);
+MAKE_FINI_FUNCTION(krb5int_lib_fini);
+
+/* Possibly load-time initialization -- mutexes, etc. */
+int krb5int_lib_init(void)
+{
+ int err;
+ err = krb5int_rc_finish_init();
+ if (err)
+ return err;
+ err = krb5int_kt_initialize();
+ if (err)
+ return err;
+ err = krb5int_cc_initialize();
+ if (err)
+ return err;
+ return 0;
+}
+
+/* Always-delayed initialization -- error table linkage, etc. */
krb5_error_code krb5int_initialize_library (void)
{
-
- if (!initialized) {
+ int err;
+
+ if (!initialized) {
#if !USE_BUNDLE_ERROR_STRINGS
- add_error_table(&et_krb5_error_table);
- add_error_table(&et_kv5m_error_table);
- add_error_table(&et_kdb5_error_table);
- add_error_table(&et_asn1_error_table);
+ add_error_table(&et_krb5_error_table);
+ add_error_table(&et_kv5m_error_table);
+ add_error_table(&et_kdb5_error_table);
+ add_error_table(&et_asn1_error_table);
#endif
+ initialized = 1;
+ }
- initialized = 1;
- }
-
- return 0;
+ return CALL_INIT_FUNCTION(krb5int_lib_init);
}
/*
- * Clean up the Kerberos v5 lirbary state
+ * Clean up the Kerberos v5 library state
*/
-void krb5int_cleanup_library (void)
+void krb5int_lib_fini(void)
{
- assert (initialized);
+ if (!INITIALIZER_RAN(krb5int_lib_init) || PROGRAM_EXITING())
+ return;
+
+ krb5int_rc_terminate();
+ krb5int_kt_finalize();
+ krb5int_cc_finalize();
+
+ if (!initialized)
+ return;
#if defined(_WIN32) || defined(USE_CCAPI)
- krb5_stdcc_shutdown();
+ krb5_stdcc_shutdown();
#endif
-
+
#if !USE_BUNDLE_ERROR_STRINGS
- remove_error_table(&et_krb5_error_table);
- remove_error_table(&et_kv5m_error_table);
- remove_error_table(&et_kdb5_error_table);
- remove_error_table(&et_asn1_error_table);
+ remove_error_table(&et_krb5_error_table);
+ remove_error_table(&et_kv5m_error_table);
+ remove_error_table(&et_kdb5_error_table);
+ remove_error_table(&et_asn1_error_table);
#endif
-
- initialized = 0;
+}
+
+/* Still exists because it went into the export list on Windows. But
+ since the above function should be invoked at unload time, we don't
+ actually want to do anything here. */
+void krb5int_cleanup_library (void)
+{
}
+2004-04-24 Ken Raeburn <raeburn@mit.edu>
+
+ * rc_base.c (rc_typelist_lock): Use new partial initializer.
+ (krb5int_rc_finish_init): New function, finish the mutex
+ initialization.
+ (krb5int_rc_terminate): New function, destroy the mutex and free
+ storage associated with registered types.
+
2004-03-05 Ken Raeburn <raeburn@mit.edu>
* rc_base.c: Include k5-thread.h.
};
static struct krb5_rc_typelist krb5_rc_typelist_dfl = { &krb5_rc_dfl_ops, 0 };
static struct krb5_rc_typelist *typehead = &krb5_rc_typelist_dfl;
-static k5_mutex_t rc_typelist_lock = K5_MUTEX_INITIALIZER;
+static k5_mutex_t rc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+int krb5int_rc_finish_init(void)
+{
+ return k5_mutex_finish_init(&rc_typelist_lock);
+}
+void krb5int_rc_terminate(void)
+{
+ struct krb5_rc_typelist *t, *t_next;
+ k5_mutex_destroy(&rc_typelist_lock);
+ for (t = typehead; t != &krb5_rc_typelist_dfl; t = t_next) {
+ t_next = t->next;
+ free(t);
+ }
+}
krb5_error_code krb5_rc_register_type(krb5_context context,
const krb5_rc_ops *ops)
+2004-04-24 Ken Raeburn <raeburn@mit.edu>
+
+ Delete support for old globally-visible linked list, necessary
+ for thread support.
+ * Makefile.in (STLIBOBJS, LINTFILES, LIBOBJS, SRCS): Drop
+ init_et.c.
+ * error_message.c: Include k5-platform.h.
+ (et_list_lock): Use new partial initializer.
+ (com_err_initialize, com_err_terminate): New init/fini functions.
+ (error_message, add_error_table, remove_error_table): Ensure the
+ initializer ran successfully.
+ * error_table.h (_et_list) [!_WIN32]: Delete declaration.
+
2004-04-22 Ken Raeburn <raeburn@mit.edu>
* libcom_err.exports: New file.
##DOS##XTRA=
##DOS##OBJFILE=$(OUTPRE)comerr.lst
-STLIBOBJS=error_message.o et_name.o init_et.o com_err.o
+STLIBOBJS=error_message.o et_name.o com_err.o
STOBJLISTS=OBJS.ST
LIB=com_err
LIBMAJOR=3
install-unix:: install-libs
LINTFLAGS=-uhvb
-LINTFILES= error_message.c et_name.c init_et.c com_err.c
+LINTFILES= error_message.c et_name.c com_err.c
LIBOBJS=$(OUTPRE)com_err.$(OBJEXT) \
$(OUTPRE)error_message.$(OBJEXT) \
- $(OUTPRE)et_name.$(OBJEXT) \
- $(OUTPRE)init_et.$(OBJEXT)
+ $(OUTPRE)et_name.$(OBJEXT)
# for et_lex.lex.c include in error_table.y
LOCALINCLUDES=-I. -I$(srcdir)
# init_et.c com_err.c
SRCS= $(srcdir)/error_message.c \
$(srcdir)/et_name.c \
- $(srcdir)/init_et.c \
$(srcdir)/com_err.c
#
#include "com_err.h"
#include "error_table.h"
#include "k5-thread.h"
+#include "k5-platform.h"
#if defined(_WIN32)
#define HAVE_STRERROR
/*@null@*/ static struct et_list * _et_list = (struct et_list *) NULL;
/*@null@*//*@only@*/static struct dynamic_et_list * et_list_dynamic;
-static k5_mutex_t et_list_lock = K5_MUTEX_INITIALIZER;
+static k5_mutex_t et_list_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+MAKE_INIT_FUNCTION(com_err_initialize);
+MAKE_FINI_FUNCTION(com_err_terminate);
+
+int com_err_initialize(void)
+{
+ return k5_mutex_finish_init(&et_list_lock);
+}
+
+void com_err_terminate(void)
+{
+ if (! INITIALIZER_RAN(com_err_initialize) || PROGRAM_EXITING())
+ return;
+ k5_mutex_destroy(&et_list_lock);
+}
#ifndef DEBUG_TABLE_LIST
#define dprintf(X)
goto system_error_code;
#endif
+ if (CALL_INIT_FUNCTION(com_err_initialize))
+ return 0;
merr = k5_mutex_lock(&et_list_lock);
if (merr)
goto oops;
struct dynamic_et_list *del;
int merr;
+ if (CALL_INIT_FUNCTION(com_err_initialize))
+ return 0;
+
del = (struct dynamic_et_list *)malloc(sizeof(struct dynamic_et_list));
if (del == NULL)
return errno;
struct et_list **el;
int merr;
+ if (CALL_INIT_FUNCTION(com_err_initialize))
+ return 0;
merr = k5_mutex_lock(&et_list_lock);
if (merr)
return merr;
/*@dependent@*//*@null@*/ struct et_list *next;
/*@dependent@*//*@null@*/ const struct error_table *table;
};
-#if !defined(_WIN32)
-/*@null@*//*@dependent@*/ extern struct et_list * _et_list;
-#endif
struct dynamic_et_list {
/*@only@*//*@null@*/ struct dynamic_et_list *next;
+2004-04-24 Ken Raeburn <raeburn@mit.edu>
+
+ * prof_file.c: Include k5-platform.h.
+ (krb5int_profile_shared_data): Now static. Use new partial mutex
+ initializer.
+ (struct global_shared_profile_data, g_shared_trees,
+ g_shared_trees_mutex): Moved here from prof_int.h.
+ (profile_library_initializer, profile_library_finalizer): New
+ init/fini functions. Deal with mutex.
+ (profile_open_file): Verify initializer ran successfully.
+
2004-04-22 Ken Raeburn <raeburn@mit.edu>
* libprofile.exports: New file.
#define stat _stat
#endif
+#include "k5-platform.h"
+
#ifdef SHARE_TREE_DATA
-struct global_shared_profile_data krb5int_profile_shared_data = {
+struct global_shared_profile_data {
+ /* This is the head of the global list of shared trees */
+ prf_data_t trees;
+ /* Lock for above list. */
+ k5_mutex_t mutex;
+};
+#define g_shared_trees (krb5int_profile_shared_data.trees)
+#define g_shared_trees_mutex (krb5int_profile_shared_data.mutex)
+
+static struct global_shared_profile_data krb5int_profile_shared_data = {
0,
- K5_MUTEX_INITIALIZER
+ K5_MUTEX_PARTIAL_INITIALIZER
};
#endif
+MAKE_INIT_FUNCTION(profile_library_initializer);
+MAKE_FINI_FUNCTION(profile_library_finalizer);
+
+int profile_library_initializer(void)
+{
+#ifdef SHARE_TREE_DATA
+ return k5_mutex_finish_init(&g_shared_trees_mutex);
+#else
+ return 0;
+#endif
+}
+void profile_library_finalizer(void)
+{
+ if (! INITIALIZER_RAN(profile_library_initializer) || PROGRAM_EXITING())
+ return;
+#ifdef SHARE_TREE_DATA
+ k5_mutex_destroy(&g_shared_trees_mutex);
+#endif
+}
+
static void profile_free_file_data(prf_data_t);
static int rw_access(profile_filespec_t filespec)
prf_data_t data;
char *expanded_filename;
+ retval = CALL_INIT_FUNCTION(profile_library_initializer);
+ if (retval)
+ return retval;
+
prf = malloc(sizeof(struct _prf_file_t));
if (!prf)
return ENOMEM;
typedef struct _prf_file_t *prf_file_t;
-#ifdef SHARE_TREE_DATA
-struct global_shared_profile_data {
- /* This is the head of the global list of shared trees */
- prf_data_t trees;
- /* Lock for above list. */
- k5_mutex_t mutex;
-};
-extern struct global_shared_profile_data krb5int_profile_shared_data;
-#define g_shared_trees (krb5int_profile_shared_data.trees)
-#define g_shared_trees_mutex (krb5int_profile_shared_data.mutex)
-
-#endif /* SHARE_TREE_DATA */
-
/*
* The profile flags
*/