From fcf02bef88a17724aa230547459a9eaf1159d6c1 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Sat, 24 Apr 2004 21:09:44 +0000 Subject: [PATCH] Added support for library initialization and finalization, and verification that the initializer completed successfully. Delay initialization on POSIX until the first "verification" call. Currently specific to a few platforms, but should still build on others without thread support enabled. Use it to finish creating (if necessary) and destroy mutexes, and free some other storage "permanently" allocated by libraries (currently, libkrb5 cache/keytab type registries only). Change initialization of static mutexes to a two-step operation, a static "partial" initializer and a "finish_init" routine called from a thread-safe environment like library initialization is assumed to be. POSIX will use the former, Windows will use the latter, and the debug support will check that *both* have been used. Added init/fini functions to com_err, profile, krb5, and gssapi libraries. (The profile library one may need to be removed later.) The existing ones, not thread-safe, are still around. Use weak symbol support if available to figure out if the pthread library has been linked in, and avoid calling certain routines if the C library stubs are known not to exist or work. Stub declarations for thread-specific data. Minor bugfixes, whitespace changes. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@16268 dc483132-0cff-0310-8789-dd5450dbe970 --- src/ChangeLog | 10 + src/aclocal.m4 | 49 ++++- src/include/ChangeLog | 43 ++++ src/include/Makefile.in | 2 +- src/include/k5-platform.h | 251 ++++++++++++++++++++++- src/include/k5-thread.h | 227 +++++++++++++++++--- src/lib/gssapi/ChangeLog | 8 + src/lib/gssapi/generic/ChangeLog | 5 + src/lib/gssapi/generic/gssapiP_generic.h | 2 +- src/lib/gssapi/gss_libinit.c | 28 ++- src/lib/gssapi/krb5/ChangeLog | 3 + src/lib/gssapi/krb5/krb5_gss_glue.c | 10 +- src/lib/krb5/ChangeLog | 11 + src/lib/krb5/ccache/ChangeLog | 8 + src/lib/krb5/ccache/ccbase.c | 20 +- src/lib/krb5/keytab/ChangeLog | 9 + src/lib/krb5/keytab/ktbase.c | 19 +- src/lib/krb5/krb/ChangeLog | 9 +- src/lib/krb5/krb/init_ctx.c | 4 +- src/lib/krb5/krb5_libinit.c | 76 +++++-- src/lib/krb5/rcache/ChangeLog | 8 + src/lib/krb5/rcache/rc_base.c | 16 +- src/util/et/ChangeLog | 13 ++ src/util/et/Makefile.in | 8 +- src/util/et/error_message.c | 25 ++- src/util/et/error_table.h | 3 - src/util/profile/ChangeLog | 11 + src/util/profile/prof_file.c | 39 +++- src/util/profile/prof_int.h | 13 -- 29 files changed, 835 insertions(+), 95 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 8b7e7aa4a..4667b492b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,6 +1,16 @@ 2004-04-24 Ken Raeburn * 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 diff --git a/src/aclocal.m4 b/src/aclocal.m4 index cf1fd8002..6dd69452e 100644 --- a/src/aclocal.m4 +++ b/src/aclocal.m4 @@ -100,7 +100,8 @@ AC_SUBST_FILE(lib_frag) 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 @@ -128,16 +129,38 @@ dnl Hack for now. 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 @@ -1042,7 +1065,7 @@ AC_REQUIRE([AC_PROG_ARCHIVE])dnl 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) @@ -1523,4 +1546,22 @@ esac 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) diff --git a/src/include/ChangeLog b/src/include/ChangeLog index cb87feb7a..279990cb3 100644 --- a/src/include/ChangeLog +++ b/src/include/ChangeLog @@ -1,3 +1,46 @@ +2004-04-24 Ken Raeburn + + * 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 * k5-int.h: krb5int_populate_gic_opt now takes credentials so it diff --git a/src/include/Makefile.in b/src/include/Makefile.in index a54505982..346b4a155 100644 --- a/src/include/Makefile.in +++ b/src/include/Makefile.in @@ -27,7 +27,7 @@ maybe-make-db.h-redirect: 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 diff --git a/src/include/k5-platform.h b/src/include/k5-platform.h index c4cc7bb75..22b38f498 100644 --- a/src/include/k5-platform.h +++ b/src/include/k5-platform.h @@ -27,8 +27,11 @@ * 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 @@ -52,6 +55,249 @@ #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 @@ -73,6 +319,7 @@ # define UINT64_TYPE unsigned long long #endif +#include #ifndef SIZE_MAX # define SIZE_MAX ((size_t)((size_t)0 - 1)) #endif diff --git a/src/include/k5-thread.h b/src/include/k5-thread.h index 27d705f79..d596e4827 100644 --- a/src/include/k5-thread.h +++ b/src/include/k5-thread.h @@ -27,25 +27,109 @@ * 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 @@ -64,9 +148,11 @@ typedef struct { 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, \ @@ -76,8 +162,12 @@ typedef struct { && (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) \ @@ -86,6 +176,13 @@ typedef struct { (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 @@ -98,8 +195,9 @@ typedef struct { #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) @@ -111,12 +209,14 @@ typedef struct { 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) @@ -124,19 +224,69 @@ typedef struct { 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 */ @@ -149,25 +299,48 @@ typedef pthread_key_t k5_key_t; 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? */ diff --git a/src/lib/gssapi/ChangeLog b/src/lib/gssapi/ChangeLog index e33541574..0c2d0ec16 100644 --- a/src/lib/gssapi/ChangeLog +++ b/src/lib/gssapi/ChangeLog @@ -1,3 +1,11 @@ +2004-04-24 Ken Raeburn + + * 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 * libgssapi_krb5.exports: New file. diff --git a/src/lib/gssapi/generic/ChangeLog b/src/lib/gssapi/generic/ChangeLog index 563eb2f06..a9f93eb14 100644 --- a/src/lib/gssapi/generic/ChangeLog +++ b/src/lib/gssapi/generic/ChangeLog @@ -1,3 +1,8 @@ +2004-04-24 Ken Raeburn + + * gssapiP_generic.h (G_SET_INIT): Use the new mutex partial + initializer now. + 2004-03-14 Ken Raeburn * gssapiP_generic.h (struct _g_set_elt, g_set_elt): Renamed from diff --git a/src/lib/gssapi/generic/gssapiP_generic.h b/src/lib/gssapi/generic/gssapiP_generic.h index 30afc5264..e297862fe 100644 --- a/src/lib/gssapi/generic/gssapiP_generic.h +++ b/src/lib/gssapi/generic/gssapiP_generic.h @@ -139,7 +139,7 @@ typedef struct { 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); diff --git a/src/lib/gssapi/gss_libinit.c b/src/lib/gssapi/gss_libinit.c index 0568f2964..fb80c8946 100644 --- a/src/lib/gssapi/gss_libinit.c +++ b/src/lib/gssapi/gss_libinit.c @@ -5,6 +5,7 @@ #include "gssapiP_krb5.h" #include "gss_libinit.h" +#include "k5-platform.h" static int initialized = 0; @@ -12,19 +13,33 @@ 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); } /* @@ -33,13 +48,12 @@ OM_uint32 gssint_initialize_library (void) 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; } diff --git a/src/lib/gssapi/krb5/ChangeLog b/src/lib/gssapi/krb5/ChangeLog index f55b779da..1be0a67a7 100644 --- a/src/lib/gssapi/krb5/ChangeLog +++ b/src/lib/gssapi/krb5/ChangeLog @@ -5,6 +5,9 @@ (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 * k5unseal.c: gss_krb5int_unseal_token_v3() takes a pointer to diff --git a/src/lib/gssapi/krb5/krb5_gss_glue.c b/src/lib/gssapi/krb5/krb5_gss_glue.c index 540652ad8..583881d8e 100644 --- a/src/lib/gssapi/krb5/krb5_gss_glue.c +++ b/src/lib/gssapi/krb5/krb5_gss_glue.c @@ -211,8 +211,14 @@ gss_import_name(minor_status, input_name_buffer, input_name_type, output_name) 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 */ diff --git a/src/lib/krb5/ChangeLog b/src/lib/krb5/ChangeLog index 35be9e437..7695a5e32 100644 --- a/src/lib/krb5/ChangeLog +++ b/src/lib/krb5/ChangeLog @@ -1,3 +1,14 @@ +2004-04-24 Ken Raeburn + + * 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 * libkrb5.exports: New file. diff --git a/src/lib/krb5/ccache/ChangeLog b/src/lib/krb5/ccache/ChangeLog index 5ab9d75a3..aacadc5ae 100644 --- a/src/lib/krb5/ccache/ChangeLog +++ b/src/lib/krb5/ccache/ChangeLog @@ -1,3 +1,11 @@ +2004-04-24 Ken Raeburn + + * 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 * ccbase.c: diff --git a/src/lib/krb5/ccache/ccbase.c b/src/lib/krb5/ccache/ccbase.c index 4fb5f8360..f635147c2 100644 --- a/src/lib/krb5/ccache/ccbase.c +++ b/src/lib/krb5/ccache/ccbase.c @@ -50,7 +50,24 @@ static struct krb5_cc_typelist cc_fcc_entry = { &krb5_cc_file_ops, &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); + } +} /* @@ -100,6 +117,7 @@ krb5_cc_register(krb5_context context, krb5_cc_ops *ops, krb5_boolean override) * particular cache type. */ +#include krb5_error_code KRB5_CALLCONV krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache) { diff --git a/src/lib/krb5/keytab/ChangeLog b/src/lib/krb5/keytab/ChangeLog index a261bf901..48855a6b7 100644 --- a/src/lib/krb5/keytab/ChangeLog +++ b/src/lib/krb5/keytab/ChangeLog @@ -1,3 +1,12 @@ +2004-04-24 Ken Raeburn + + * 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 * ktbase.c: diff --git a/src/lib/krb5/keytab/ktbase.c b/src/lib/krb5/keytab/ktbase.c index 79c20ece9..74ff20cf6 100644 --- a/src/lib/krb5/keytab/ktbase.c +++ b/src/lib/krb5/keytab/ktbase.c @@ -52,7 +52,23 @@ const static struct krb5_kt_typelist krb5_kt_typelist_srvtab = { }; 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); + } +} /* @@ -97,6 +113,7 @@ krb5_kt_register(krb5_context context, const krb5_kt_ops *ops) * particular keytab type. */ +#include krb5_error_code KRB5_CALLCONV krb5_kt_resolve (krb5_context context, const char *name, krb5_keytab *ktid) { diff --git a/src/lib/krb5/krb/ChangeLog b/src/lib/krb5/krb/ChangeLog index e36fced37..2d4ef8bef 100644 --- a/src/lib/krb5/krb/ChangeLog +++ b/src/lib/krb5/krb/ChangeLog @@ -1,7 +1,12 @@ -2004-04-16 Sam Hartman +2004-04-24 Ken Raeburn + + * init_ctx.c (init_common): In UNIX case, check the return value + from krb5int_initialize_library. +2004-04-16 Sam Hartman - * 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 diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c index 2740d8361..de6b22d50 100644 --- a/src/lib/krb5/krb/init_ctx.c +++ b/src/lib/krb5/krb/init_ctx.c @@ -128,7 +128,9 @@ init_common (krb5_context *context, krb5_boolean secure) if (retval) return retval; #else /* assume UNIX for now */ - krb5int_initialize_library (); + retval = krb5int_initialize_library (); + if (retval) + return retval; #endif *context = 0; diff --git a/src/lib/krb5/krb5_libinit.c b/src/lib/krb5/krb5_libinit.c index 3e2890896..6b7bf23ef 100644 --- a/src/lib/krb5/krb5_libinit.c +++ b/src/lib/krb5/krb5_libinit.c @@ -13,6 +13,7 @@ #endif #include "krb5_libinit.h" +#include "k5-platform.h" static int initialized = 0; @@ -20,41 +21,74 @@ 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) +{ } diff --git a/src/lib/krb5/rcache/ChangeLog b/src/lib/krb5/rcache/ChangeLog index a096114f2..870054477 100644 --- a/src/lib/krb5/rcache/ChangeLog +++ b/src/lib/krb5/rcache/ChangeLog @@ -1,3 +1,11 @@ +2004-04-24 Ken Raeburn + + * 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 * rc_base.c: Include k5-thread.h. diff --git a/src/lib/krb5/rcache/rc_base.c b/src/lib/krb5/rcache/rc_base.c index 5758c20bc..f26b359a9 100644 --- a/src/lib/krb5/rcache/rc_base.c +++ b/src/lib/krb5/rcache/rc_base.c @@ -22,7 +22,21 @@ struct krb5_rc_typelist { }; 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) diff --git a/src/util/et/ChangeLog b/src/util/et/ChangeLog index 358d9246d..4df5b54cf 100644 --- a/src/util/et/ChangeLog +++ b/src/util/et/ChangeLog @@ -1,3 +1,16 @@ +2004-04-24 Ken Raeburn + + 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 * libcom_err.exports: New file. diff --git a/src/util/et/Makefile.in b/src/util/et/Makefile.in index ce2cec44d..50fd0c2ac 100644 --- a/src/util/et/Makefile.in +++ b/src/util/et/Makefile.in @@ -14,7 +14,7 @@ SED = sed ##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 @@ -25,11 +25,10 @@ clean-unix:: clean-liblinks clean-libs clean-libobjs clean-lclint 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) @@ -45,7 +44,6 @@ FILES= Makefile et_name.c error_message.c compile_et.c \ # init_et.c com_err.c SRCS= $(srcdir)/error_message.c \ $(srcdir)/et_name.c \ - $(srcdir)/init_et.c \ $(srcdir)/com_err.c # diff --git a/src/util/et/error_message.c b/src/util/et/error_message.c index 67b62ee66..cf8fe53aa 100644 --- a/src/util/et/error_message.c +++ b/src/util/et/error_message.c @@ -27,6 +27,7 @@ #include "com_err.h" #include "error_table.h" #include "k5-thread.h" +#include "k5-platform.h" #if defined(_WIN32) #define HAVE_STRERROR @@ -41,7 +42,22 @@ static char buffer[ET_EBUFSIZ]; /*@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) @@ -101,6 +117,8 @@ error_message(long code) 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; @@ -230,6 +248,9 @@ add_error_table(/*@dependent@*/ const struct error_table * et) 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; @@ -256,6 +277,8 @@ remove_error_table(const struct error_table * et) 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; diff --git a/src/util/et/error_table.h b/src/util/et/error_table.h index 9e1d26fa5..41453587c 100644 --- a/src/util/et/error_table.h +++ b/src/util/et/error_table.h @@ -15,9 +15,6 @@ struct et_list { /*@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; diff --git a/src/util/profile/ChangeLog b/src/util/profile/ChangeLog index 13828007c..76a984a7e 100644 --- a/src/util/profile/ChangeLog +++ b/src/util/profile/ChangeLog @@ -1,3 +1,14 @@ +2004-04-24 Ken Raeburn + + * 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 * libprofile.exports: New file. diff --git a/src/util/profile/prof_file.c b/src/util/profile/prof_file.c index 1141127a1..12771d234 100644 --- a/src/util/profile/prof_file.c +++ b/src/util/profile/prof_file.c @@ -27,13 +27,44 @@ #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) @@ -96,6 +127,10 @@ errcode_t profile_open_file(const_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; diff --git a/src/util/profile/prof_int.h b/src/util/profile/prof_int.h index a0d90b5e2..c6ec667ac 100644 --- a/src/util/profile/prof_int.h +++ b/src/util/profile/prof_int.h @@ -54,19 +54,6 @@ struct _prf_file_t { 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 */ -- 2.26.2