MAKE_INIT_FUNCTION(krb5int_thread_support_init);
MAKE_FINI_FUNCTION(krb5int_thread_support_fini);
-\f
-#ifdef ENABLE_THREADS
+#ifndef ENABLE_THREADS /* no thread support */
-#ifdef _WIN32
-
-static DWORD tls_idx;
-CRITICAL_SECTION key_lock;
static void (*destructors[K5_KEY_MAX])(void *);
+struct tsd_block { void *values[K5_KEY_MAX]; };
+static struct tsd_block tsd_no_threads;
static unsigned char destructors_set[K5_KEY_MAX];
-int krb5int_thread_support_init (void)
-{
- tls_idx = TlsAlloc();
- /* XXX This can raise an exception if memory is low! */
- InitializeCriticalSection(&key_lock);
- return 0;
-}
-
-void krb5int_thread_support_fini (void)
-{
- if (! INITIALIZER_RAN (krb5int_thread_support_init))
- return;
- /* ... free stuff ... */
- TlsFree(tls_idx);
- DeleteCriticalSection(&key_lock);
-}
-
-int k5_key_register (k5_key_t keynum, void (*destructor)(void *))
-{
- DWORD wait_result;
+#elif defined(_WIN32)
- assert(keynum >= 0 && keynum < K5_KEY_MAX);
- /* XXX: This can raise EXCEPTION_POSSIBLE_DEADLOCK. */
- EnterCriticalSection(&key_lock);
- assert(destructors_set[keynum] == 0);
- destructors_set[keynum] = 1;
- destructors[keynum] = destructor;
- LeaveCriticalSection(&key_lock);
- return 0;
-}
+static DWORD tls_idx;
+static CRITICAL_SECTION key_lock;
+static void (*destructors[K5_KEY_MAX])(void *);
+static unsigned char destructors_set[K5_KEY_MAX];
-void *k5_getspecific (k5_key_t keynum)
+void krb5int_thread_detach_hook (void)
{
+ /* XXX Memory leak here!
+ Need to destroy all TLS objects we know about for this thread. */
struct tsd_block *t;
+ int i, err;
err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
if (err)
- return NULL;
-
- assert(keynum >= 0 && keynum < K5_KEY_MAX);
+ return;
t = TlsGetValue(tls_idx);
if (t == NULL)
- return NULL;
- return t->values[keynum];
-}
-
-int k5_setspecific (k5_key_t keynum, void *value)
-{
- struct tsd_block *t;
-
- err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
- if (err)
- return NULL;
-
- assert(keynum >= 0 && keynum < K5_KEY_MAX);
-
- t = TlsGetValue(tls_idx);
- if (t == NULL) {
- int i;
- t = malloc(sizeof(*t));
- if (t == NULL)
- return errno;
- for (i = 0; i < K5_KEY_MAX; i++)
+ return;
+ 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;
- /* add to global linked list */
- t->next = 0;
- err = TlsSetValue(key, t);
- if (err) {
- free(t);
- return err;
+ (*destructors[i])(v);
}
}
- t->values[keynum] = value;
- return 0;
-}
-
-int k5_key_delete (k5_key_t keynum)
-{
- assert(keynum >= 0 && keynum < K5_KEY_MAX);
- /* XXX: This can raise EXCEPTION_POSSIBLE_DEADLOCK. */
- EnterCriticalSection(&key_lock);
- abort();
- LeaveCriticalSection(&key_lock);
- return 0;
-}
-
-void krb5int_thread_detach_hook (void)
-{
- /* XXX Memory leak here!
- Need to destroy all TLS objects we know about for this thread. */
}
-\f
-#else
-
-/* POSIX */
+#else /* POSIX threads */
/* Must support register/delete/register sequence, e.g., if krb5 is
loaded so this support code stays in the process, and gssapi is
# pragma weak pthread_key_create
# pragma weak pthread_key_delete
static struct tsd_block tsd_if_single;
+# define GET_NO_PTHREAD_TSD() (&tsd_if_single)
+#else
+# define GET_NO_PTHREAD_TSD() (abort(),0)
#endif
static pthread_key_t key;
static void thread_termination(void *);
-int krb5int_thread_support_init(void)
-{
- int err;
- err = k5_mutex_finish_init(&key_lock);
- if (err)
- return err;
- if (K5_PTHREADS_LOADED)
- return pthread_key_create(&key, thread_termination);
- else
- return 0;
-}
-
-void krb5int_thread_support_fini(void)
-{
- if (! INITIALIZER_RAN(krb5int_thread_support_init))
- return;
- if (K5_PTHREADS_LOADED)
- pthread_key_delete(key);
- /* ... delete stuff ... */
- k5_mutex_destroy(&key_lock);
-}
-
static void thread_termination (void *tptr)
{
int i, pass, none_found;
/* remove thread from global linked list */
}
-int k5_key_register (k5_key_t keynum, void (*destructor)(void *))
-{
- int err;
-
- err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
- if (err)
- return err;
- err = k5_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 = k5_mutex_unlock(&key_lock);
- if (err)
- return err;
- return 0;
-}
+#endif /* no threads vs Win32 vs POSIX */
void *k5_getspecific (k5_key_t keynum)
{
return NULL;
assert(keynum >= 0 && keynum < K5_KEY_MAX);
- assert(destructors_set[keynum] != 0);
+ assert(destructors_set[keynum] == 1);
+
+#ifndef ENABLE_THREADS
+
+ t = &tsd_no_threads;
+
+#elif defined(_WIN32)
+
+ t = TlsGetValue(tls_idx);
+
+#else /* POSIX */
if (K5_PTHREADS_LOADED)
t = pthread_getspecific(key);
- else {
-#ifdef HAVE_PRAGMA_WEAK_REF
- t = &tsd_if_single;
-#else
- abort();
-#endif
+ else
+ t = GET_NO_PTHREAD_TSD();
}
+
+#endif
+
if (t == NULL)
return NULL;
-
return t->values[keynum];
}
return err;
assert(keynum >= 0 && keynum < K5_KEY_MAX);
- assert(destructors_set[keynum] != 0);
+ assert(destructors_set[keynum] == 1);
+
+#ifndef ENABLE_THREADS
+
+ t = &tsd_no_threads;
+
+#elif defined(_WIN32)
+
+ t = TlsGetValue(tls_idx);
+ 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 = TlsSetValue(key, t);
+ if (err) {
+ free(t);
+ return err;
+ }
+ }
+
+#else /* POSIX */
if (K5_PTHREADS_LOADED) {
t = pthread_getspecific(key);
}
}
} else {
-#ifdef HAVE_PRAGMA_WEAK_REF
- t = &tsd_if_single;
-#else
- abort();
-#endif
+ t = GET_NO_PTHREAD_TSD();
}
+#endif
+
t->values[keynum] = value;
return 0;
}
-int k5_key_delete (k5_key_t keynum)
+int k5_key_register (k5_key_t keynum, void (*destructor)(void *))
{
- abort();
-}
+ int err;
-#endif /* Win32 vs POSIX */
+ err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
+ if (err)
+ return err;
-\f
-#else
-/* no thread support */
+ assert(keynum >= 0 && keynum < K5_KEY_MAX);
-static void (*destructors[K5_KEY_MAX])(void *);
-static void *tsd_values[K5_KEY_MAX];
-static unsigned char destructors_set[K5_KEY_MAX];
+#ifndef ENABLE_THREADS
-int krb5int_thread_support_init(void)
-{
- return 0;
-}
+ assert(destructors_set[keynum] == 0);
+ destructors[keynum] = destructor;
+ destructors_set[keynum] = 1;
+ err = 0;
-void krb5int_thread_support_fini(void)
-{
- /* ... */
-}
+#elif defined(_WIN32)
-int k5_key_register (k5_key_t keynum, void (*d)(void *))
-{
- assert(keynum >= 0 && keynum < K5_KEY_MAX);
+ /* XXX: This can raise EXCEPTION_POSSIBLE_DEADLOCK. */
+ EnterCriticalSection(&key_lock);
assert(destructors_set[keynum] == 0);
- destructors[keynum] = d;
destructors_set[keynum] = 1;
- return 0;
-}
+ destructors[keynum] = destructor;
+ LeaveCriticalSection(&key_lock);
+ err = 0;
-void *k5_getspecific (k5_key_t keynum)
-{
- assert(keynum >= 0 && keynum < K5_KEY_MAX);
- assert(destructors_set[keynum] == 1);
- return tsd_values[keynum];
-}
+#else /* POSIX */
-int k5_setspecific (k5_key_t keynum, void *value)
-{
- assert(keynum >= 0 && keynum < K5_KEY_MAX);
- assert(destructors_set[keynum] == 1);
- tsd_values[keynum] = value;
+ err = k5_mutex_lock(&key_lock);
+ if (err == 0) {
+ assert(destructors_set[keynum] == 0);
+ destructors_set[keynum] = 1;
+ destructors[keynum] = destructor;
+ err = k5_mutex_unlock(&key_lock);
+ }
+
+#endif
return 0;
}
int k5_key_delete (k5_key_t keynum)
{
assert(keynum >= 0 && keynum < K5_KEY_MAX);
+
+#ifndef ENABLE_THREADS
+
assert(destructors_set[keynum] == 1);
- if (destructors[keynum] && tsd_values[keynum])
- (*destructors[keynum])(tsd_values[keynum]);
+ if (destructors[keynum] && tsd_no_threads.values[keynum])
+ (*destructors[keynum])(tsd_no_threads.values[keynum]);
destructors[keynum] = 0;
- tsd_values[keynum] = 0;
+ tsd_no_threads.values[keynum] = 0;
destructors_set[keynum] = 0;
+
+#elif defined(_WIN32)
+
+ /* XXX: This can raise EXCEPTION_POSSIBLE_DEADLOCK. */
+ EnterCriticalSection(&key_lock);
+ /* XXX Memory leak here!
+ Need to destroy the associated data for all threads.
+ But watch for race conditions in case threads are going away too. */
+ LeaveCriticalSection(&key_lock);
+
+#else /* POSIX */
+
+ /* Not written yet. */
+ abort();
+
+#endif
+
return 0;
}
+int krb5int_thread_support_init (void)
+{
+#ifndef ENABLE_THREADS
+
+ return 0;
+
+#elif defined(_WIN32)
+
+ tls_idx = TlsAlloc();
+ /* XXX This can raise an exception if memory is low! */
+ InitializeCriticalSection(&key_lock);
+ return 0;
+
+#else /* POSIX */
+
+ int err;
+ err = k5_mutex_finish_init(&key_lock);
+ if (err)
+ return err;
+ if (K5_PTHREADS_LOADED)
+ return pthread_key_create(&key, thread_termination);
+ else
+ return 0;
+
#endif
+}
+
+void krb5int_thread_support_fini (void)
+{
+#ifndef ENABLE_THREADS
+
+ /* Do nothing. */
+
+#elif defined(_WIN32)
+
+ if (! INITIALIZER_RAN (krb5int_thread_support_init))
+ return;
+ /* ... free stuff ... */
+ TlsFree(tls_idx);
+ DeleteCriticalSection(&key_lock);
+
+#else /* POSIX */
+
+ if (! INITIALIZER_RAN(krb5int_thread_support_init))
+ return;
+ if (K5_PTHREADS_LOADED)
+ pthread_key_delete(key);
+ /* ... delete stuff ... */
+ k5_mutex_destroy(&key_lock);
+
+#endif
+}
+