mit-krb5 thread support: thread-specific data
Ken Raeburn
raeburn at MIT.EDU
Tue Apr 6 09:51:31 EDT 2004
Unlike mutexes, where we'll need to be able to create one per replay
cache or credentials cache object, the number of cases where
per-thread data is needed is limited, and can be enumerated in the
code. The overhead of making a few tables large enough to include
support for GSSAPI thread-specific data even in an application that
doesn't use GSSAPI shouldn't be significant.
Here's the internal API I propose, though since I haven't started
implementing it yet (probably will today), it may need a bit of
polish:
// 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);
// 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, const 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. Calling k5_key_register a second time on a given
key value, without an intervening k5_key_delete call, is an error.
Note that the C library routine free() has a compatible signature and
could be used directly as a destructor function.
On POSIX, we can use pthread_getspecific and friends to give us a
per-thread array of pointers indexed by key number. This means the
Kerberos code all together will require only one key at the POSIX
level, which is helpful since POSIX lets a system limit the keys
available to a fairly small number.
These arrays will also be referenced from some global table that can
be walked when a library gets unloaded, to implement k5_key_delete. I
believe pretty much all UNIX shared library systems these days support
some sort of initialization and finalization operations, though we may
need system-specific mechanisms for setting them up. (If they don't
have the support, can they support initialization of C++ static
objects in dynamically loadable libraries? If they support C++, we
may be able to use a C++ source file to build on that support, if no
better approach is available.)
On Windows, library support functions can be invoked on thread
termination and library unloading; we can use this to either walk
through a set of pointers for a thread's specific data, or for each
thread destroy the data it associates with a given key. That assumes
we've got DLL support, at least for the krb5 thread support code, and
aren't linking everything together statically. (Is that a reasonable
assumption?)
As with the mutex support, 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).
Comments?
Ken
More information about the krbdev
mailing list