summaryrefslogtreecommitdiff
path: root/ptw32_callUserDestroyRoutines.c
diff options
context:
space:
mode:
Diffstat (limited to 'ptw32_callUserDestroyRoutines.c')
-rw-r--r--ptw32_callUserDestroyRoutines.c184
1 files changed, 95 insertions, 89 deletions
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);
}