From 99aebd430a3a4f037cc10d14751afcb99fe0365f Mon Sep 17 00:00:00 2001 From: rpj Date: Mon, 9 May 2005 08:32:18 +0000 Subject: '' --- manual/pthread_key_create.html | 42 ++++++--- ptw32_callUserDestroyRoutines.c | 184 +++++++++++++++++++++------------------- 2 files changed, 123 insertions(+), 103 deletions(-) diff --git a/manual/pthread_key_create.html b/manual/pthread_key_create.html index 9d9e004..5ecca69 100644 --- a/manual/pthread_key_create.html +++ b/manual/pthread_key_create.html @@ -5,7 +5,7 @@ PTHREAD_SPECIFIC(3) manual page - + @@ -60,9 +60,9 @@ in all currently executing threads. a destructor function associated with the key. When a thread terminates via pthread_exit or by cancellation, destr_function is called with arguments the value associated with the key in that -thread. The destr_function is not called if that value is -NULL. The order in which destructor functions are called at -thread termination time is unspecified. +thread. The destr_function is not called if that value is NULL +or the key has been deleted. The order in which destructor +functions are called at thread termination time is unspecified.

Before the destructor function is called, the NULL value is associated with the key in the current thread. A destructor function @@ -70,11 +70,7 @@ might, however, re-associate non- NULL values to that key or some other key. To deal with this, if after all the destructors have been called for all non- NULL values, there are still some non- NULL values with associated destructors, then the process -is repeated. The Pthreads-w32 implementation stops the process after -PTHREAD_DESTRUCTOR_ITERATIONS iterations, even if some non- -NULL values with associated descriptors remain. Other -implementations may loop indefinitely. -

+is repeated.

pthread_key_delete deallocates a TSD key. It does not check whether non- NULL values are associated with that key in the currently executing threads, nor call the destructor function @@ -86,6 +82,24 @@ in the calling thread, storing the given pointer instead.

pthread_getspecific returns the value currently associated with key in the calling thread.

+

The routines pthread_setspecific, pthread_getspecific, +and pthread_key_delete can be called from destr_function +targeting any valid key including the key on which destr_function +is currently operating. If pthread_getspecific is called on +the key whose thread specific data is being destroyed, the value NULL +is returned, unless pthread_setspecific was called previously +on that key from within destr_function to set the value to +non-NULL. For some implementations the effect of calling +pthread_setspecific from within destr_function can be +either memory leakage or infinite loops if destr_function has +already been called at least PTHREAD_DESTRUCTOR_ITERATIONS +times.

+

Pthreads-w32 stops running key +destr_function routines after PTHREAD_DESTRUCTOR_ITERATIONS +iterations, even if some non- NULL values with associated +descriptors remain. If memory is allocated and associated with a key +from within destr_function, that memory may not be reclaimed +because that key's destr_function, may not run again.

Return Value

pthread_key_create, pthread_key_delete, and pthread_setspecific return 0 on success and a non-zero error @@ -105,7 +119,7 @@ error:

EAGAIN
-
+
PTHREAD_KEYS_MAX keys are already allocated
@@ -113,7 +127,7 @@ error:
ENOMEM
-
+
Insufficient memory to allocate the key.

pthread_key_delete and pthread_setspecific return @@ -171,8 +185,8 @@ static void buffer_destroy(void * buf) free(buf); }


-
Table of -Contents
+
+Table of Contents
  • Name
    @@ -194,4 +208,4 @@ Contents
- + \ No newline at end of file diff --git a/ptw32_callUserDestroyRoutines.c b/ptw32_callUserDestroyRoutines.c index cdec87e..a583f18 100644 --- a/ptw32_callUserDestroyRoutines.c +++ b/ptw32_callUserDestroyRoutines.c @@ -77,10 +77,6 @@ ptw32_callUserDestroyRoutines (pthread_t thread) * for the current thread. * * Do this process at most PTHREAD_DESTRUCTOR_ITERATIONS times. - * - * First we need to serialise with pthread_key_delete by locking - * both assoc guards, but in the reverse order to normal, and so - * we must be careful to avoid deadlock. */ do { @@ -89,125 +85,135 @@ ptw32_callUserDestroyRoutines (pthread_t thread) (void) pthread_mutex_lock(&(sp->threadLock)); /* - * The next assoc pointer is stored in the thread struct so that + * The pointer to the next assoc is stored in the thread struct so that * the assoc destructor in pthread_key_delete can adjust it * if it deletes this assoc. This can happen if we fail to acquire * both locks below, and are forced to release all of our locks, - * leaving open the opportunity. + * leaving open the opportunity for pthread_key_delete to get in + * before us. */ sp->nextAssoc = sp->keys; (void) pthread_mutex_unlock(&(sp->threadLock)); - for (;;) - { - void * value; - pthread_key_t k; - void (*destructor) (void *); - - (void) pthread_mutex_lock(&(sp->threadLock)); - - if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL) - { - /* Finished */ - pthread_mutex_unlock(&(sp->threadLock)); - break; - } - else + for (;;) { + void * value; + pthread_key_t k; + void (*destructor) (void *); + /* - * assoc->key must be valid because assoc can't change or be - * removed from our chain while we hold at least one lock. If - * the assoc was on our key chain then the key has not been - * deleted yet. - * - * Try to acquire both locks without deadlocking. + * First we need to serialise with pthread_key_delete by locking + * both assoc guards, but in the reverse order to our convention, + * so we must be careful to avoid deadlock. */ - if (pthread_mutex_trylock(&(assoc->key->keyLock)) == EBUSY) + (void) pthread_mutex_lock(&(sp->threadLock)); + + if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL) { + /* Finished */ pthread_mutex_unlock(&(sp->threadLock)); - Sleep(1); // Ugly. + break; + } + else + { /* - * Go around again. - * If pthread_key_delete has removed this assoc in the meantime, - * sp->keys will point to a new assoc. + * assoc->key must be valid because assoc can't change or be + * removed from our chain while we hold at least one lock. If + * the assoc was on our key chain then the key has not been + * deleted yet. + * + * Now try to acquire the second lock without deadlocking. + * If we fail, we need to relinquish the first lock and the + * processor and then try to acquire them all again. */ - continue; + if (pthread_mutex_trylock(&(assoc->key->keyLock)) == EBUSY) + { + pthread_mutex_unlock(&(sp->threadLock)); + Sleep(1); // Ugly but necessary to avoid priority effects. + /* + * Go around again. + * If pthread_key_delete has removed this assoc in the meantime, + * sp->nextAssoc will point to a new assoc. + */ + continue; + } } - } - - /* We now hold both locks */ - sp->nextAssoc = assoc->nextKey; + /* We now hold both locks */ - /* - * Key still active; pthread_key_delete - * will block on these same mutexes before - * it can release actual key; therefore, - * key is valid and we can call the destroy - * routine; - */ - k = assoc->key; - destructor = k->destructor; - value = TlsGetValue(k->key); - TlsSetValue (k->key, NULL); + sp->nextAssoc = assoc->nextKey; - // Every assoc->key exists and has a destructor - if (value != NULL && iterations <= PTHREAD_DESTRUCTOR_ITERATIONS) - { /* - * Unlock both locks before the destructor runs. - * POSIX says pthread_key_delete can be run from destructors, - * and that probably includes with this key as target. + * Key still active; pthread_key_delete + * will block on these same mutexes before + * it can release actual key; therefore, + * key is valid and we can call the destroy + * routine; */ - (void) pthread_mutex_unlock(&(sp->threadLock)); - (void) pthread_mutex_unlock(&(k->keyLock)); + k = assoc->key; + destructor = k->destructor; + value = TlsGetValue(k->key); + TlsSetValue (k->key, NULL); + + // Every assoc->key exists and has a destructor + if (value != NULL && iterations <= PTHREAD_DESTRUCTOR_ITERATIONS) + { + /* + * Unlock both locks before the destructor runs. + * POSIX says pthread_key_delete can be run from destructors, + * and that probably includes with this key as target. + * pthread_setspecific can also be run from destructors and + * also needs to be able to access the assocs. + */ + (void) pthread_mutex_unlock(&(sp->threadLock)); + (void) pthread_mutex_unlock(&(k->keyLock)); - assocsRemaining++; + assocsRemaining++; #ifdef __cplusplus - try - { + try + { + /* + * Run the caller's cleanup routine. + */ + destructor (value); + } + catch (...) + { + /* + * A system unexpected exception has occurred + * running the user's destructor. + * We get control back within this block in case + * the application has set up it's own terminate + * handler. Since we are leaving the thread we + * should not get any internal pthreads + * exceptions. + */ + terminate (); + } + +#else /* __cplusplus */ + /* * Run the caller's cleanup routine. */ destructor (value); + +#endif /* __cplusplus */ + } - catch (...) + else { /* - * A system unexpected exception has occurred - * running the user's destructor. - * We get control back within this block in case - * the application has set up it's own terminate - * handler. Since we are leaving the thread we - * should not get any internal pthreads - * exceptions. + * Remove association from both the key and thread chains + * and reclaim it's memory resources. */ - terminate (); + ptw32_tkAssocDestroy (assoc); + (void) pthread_mutex_unlock(&(sp->threadLock)); + (void) pthread_mutex_unlock(&(k->keyLock)); } - -#else /* __cplusplus */ - - /* - * Run the caller's cleanup routine. - */ - destructor (value); - -#endif /* __cplusplus */ - } - else - { - /* - * Remove association from both the key and thread chains - * and reclaim it's memory resources. - */ - ptw32_tkAssocDestroy (assoc); - (void) pthread_mutex_unlock(&(sp->threadLock)); - (void) pthread_mutex_unlock(&(k->keyLock)); - } - } } while (assocsRemaining); } -- cgit v1.2.3