diff options
author | Ken Raeburn <raeburn@mit.edu> | 2004-05-04 22:40:07 +0000 |
---|---|---|
committer | Ken Raeburn <raeburn@mit.edu> | 2004-05-04 22:40:07 +0000 |
commit | 3808c842f799ee522d408d9eb34c1dbd45a07fa2 (patch) | |
tree | b90326bcc5a7587d90b208a0a96413702d89f3c9 /src/util/support/threads.c | |
parent | 78baf0d2da15305afe0f6ccf17f38fb3a3d9cc8c (diff) | |
download | krb5-3808c842f799ee522d408d9eb34c1dbd45a07fa2.zip krb5-3808c842f799ee522d408d9eb34c1dbd45a07fa2.tar.gz krb5-3808c842f799ee522d408d9eb34c1dbd45a07fa2.tar.bz2 |
* New directory.
* Makefile.in: New file.
* threads.c: New file. Thread-specific data support.
* fake-addrinfo.c: New file. Placeholder.
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@16299 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/util/support/threads.c')
-rw-r--r-- | src/util/support/threads.c | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/util/support/threads.c b/src/util/support/threads.c new file mode 100644 index 0000000..2aede85 --- /dev/null +++ b/src/util/support/threads.c @@ -0,0 +1,237 @@ +/* + * util/support/threads.c + * + * Copyright 2004 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * Preliminary thread support. + */ + +#include <assert.h> +#include <stdlib.h> +#include <errno.h> +#include "k5-thread.h" +#include "k5-platform.h" + +MAKE_INIT_FUNCTION(krb5int_thread_support_init); +MAKE_FINI_FUNCTION(krb5int_thread_support_fini); + +#ifdef ENABLE_THREADS + +#ifdef _WIN32 + +#error "need WIN32 thread support code written" + +#else + +/* POSIX */ + +/* Must support register/delete/register sequence, e.g., if krb5 is + loaded so this support code stays in the process, and gssapi is + loaded, unloaded, and loaded again. */ + +static pthread_mutex_t key_lock = PTHREAD_MUTEX_INITIALIZER; +static void (*destructors[K5_KEY_MAX])(void *); +static unsigned char destructors_set[K5_KEY_MAX]; + +/* This is not safe yet! + + Thread termination concurrent with key deletion can cause two + threads to interfere. It's a bit tricky, since one of the threads + will want to remove this structure from the list being walked by + the other. + + Other cases, like looking up data while the library owning the key + is in the process of being unloaded, we don't worry about. */ + +struct tsd_block { + struct tsd_block *next; + void *values[K5_KEY_MAX]; +}; + +static pthread_key_t key; +static void thread_termination(void *); + +int krb5int_thread_support_init(void) +{ + return pthread_key_create(&key, thread_termination); +} + +void krb5int_thread_support_fini(void) +{ + if (INITIALIZER_RAN(krb5int_thread_support_init)) + pthread_key_delete(key); +} + +static void thread_termination (void *tptr) +{ + int i, pass, none_found; + struct tsd_block *t = tptr; + + /* Make multiple passes in case, for example, a libkrb5 cleanup + function wants to print out an error message, which causes + com_err to allocate a thread-specific buffer, after we just + freed up the old one. + + Shouldn't actually happen, if we're careful, but check just in + case. */ + + pass = 0; + none_found = 0; + while (pass < 4 && !none_found) { + none_found = 1; + for (i = 0; i < K5_KEY_MAX; i++) { + if (destructors_set[i] && destructors[i] && t->values[i]) { + void *v = t->values[i]; + t->values[i] = 0; + (*destructors[i])(v); + none_found = 0; + } + } + } + /* remove thread from global linked list */ +} + +int k5_key_register (k5_key_t keynum, void (*destructor)(void *)) +{ + int err; + + err = pthread_mutex_lock(&key_lock); + if (err) + return err; + assert(keynum >= 0 && keynum < K5_KEY_MAX); + assert(destructors_set[keynum] == 0); + destructors_set[keynum] = 1; + destructors[keynum] = destructor; + err = pthread_mutex_unlock(&key_lock); + if (err) + return err; + return 0; +} + +void *k5_getspecific (k5_key_t keynum) +{ + struct tsd_block *t; + int err; + + err = CALL_INIT_FUNCTION(krb5int_thread_support_init); + if (err) + return NULL; + + assert(keynum >= 0 && keynum < K5_KEY_MAX); + assert(destructors_set[keynum] != 0); + + t = pthread_getspecific(key); + if (t == NULL) + return NULL; + + return t->values[keynum]; +} + +int k5_setspecific (k5_key_t keynum, void *value) +{ + struct tsd_block *t; + int err; + + err = CALL_INIT_FUNCTION(krb5int_thread_support_init); + if (err) + return err; + + assert(keynum >= 0 && keynum < K5_KEY_MAX); + assert(destructors_set[keynum] != 0); + + t = pthread_getspecific(key); + if (t == NULL) { + int i; + t = malloc(sizeof(*t)); + if (t == NULL) + return errno; + for (i = 0; i < K5_KEY_MAX; i++) + t->values[i] = 0; + /* add to global linked list */ + t->next = 0; + err = pthread_setspecific(key, t); + if (err) { + free(t); + return err; + } + } + + t->values[keynum] = value; + return 0; +} + +int k5_key_delete (k5_key_t keynum) +{ + abort(); +} + +#endif /* Win32 vs POSIX */ + +#else + +static void (*destructors[K5_KEY_MAX])(void); +static void *tsd_values[K5_KEY_MAX]; +static unsigned char destructors_set[K5_KEY_MAX]; + +int krb5int_thread_support_init(void) +{ + return 0; +} + +int k5_key_register (k5_key_t keynum, void (*d)(void)) +{ + assert(keynum >= 0 && keynum < K5_KEY_MAX); + assert(destructors_set[keynum] == 0); + destructors[keynum] = d; + destructors_set[keynum] = 1; +} + +void *k5_getspecific (k5_key_t keynum) +{ + assert(keynum >= 0 && keynum < K5_KEY_MAX); + assert(destructors_set[keynum] == 1); + return tsd_values[keynum]; +} + +int k5_setspecific (k5_key_t keynum, const void *value) +{ + assert(keynum >= 0 && keynum < K5_KEY_MAX); + assert(destructors_set[keynum] == 1); + tsd_values[keynum] = value; + return 0; +} + +int k5_key_delete (k5_key_t keynum) +{ + assert(keynum >= 0 && keynum < K5_KEY_MAX); + assert(destructors_set[keynum] == 1); + if (destructors[keynum] && tsd_values[keynum]) + (*destructors[keynum])(tsd_values[keynum]); + destructors[keynum] = 0; + tsd_values[keynum] = 0; + destructors_set[keynum] = 0; + return 0; +} + +#endif |