summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrpj <rpj>2005-05-09 08:31:31 +0000
committerrpj <rpj>2005-05-09 08:31:31 +0000
commit6961e1741a9bdcff4b075859acc15e56031889a3 (patch)
treea31b393d3d9e3c2ec95b5c5d24ab797569a027d2
parent7395b1431d5e2160682de273b46252c747ccbf36 (diff)
''
-rw-r--r--manual/pthread_key_create.html42
-rw-r--r--ptw32_callUserDestroyRoutines.c184
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 @@
<TITLE>PTHREAD_SPECIFIC(3) manual page</TITLE>
<META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.3 (Linux)">
<META NAME="CREATED" CONTENT="20050504;18425400">
- <META NAME="CHANGED" CONTENT="20050505;18330000">
+ <META NAME="CHANGED" CONTENT="20050509;18220200">
<!-- manual page source format generated by PolyglotMan v3.2, -->
<!-- available at http://polyglotman.sourceforge.net/ -->
</HEAD>
@@ -60,9 +60,9 @@ in all currently executing threads.
a destructor function associated with the key. When a thread
terminates via <B>pthread_exit</B> or by cancellation, <I>destr_function</I>
is called with arguments the value associated with the key in that
-thread. The <I>destr_function</I> is not called if that value is
-<B>NULL</B>. The order in which destructor functions are called at
-thread termination time is unspecified.
+thread. The <I>destr_function</I> is not called if that value is <B>NULL</B><SPAN STYLE="font-weight: medium">
+or the key has been deleted</SPAN>. The order in which destructor
+functions are called at thread termination time is unspecified.
</P>
<P>Before the destructor function is called, the <B>NULL</B> value is
associated with the key in the current thread. A destructor function
@@ -70,11 +70,7 @@ might, however, re-associate non- <B>NULL</B> values to that key or
some other key. To deal with this, if after all the destructors have
been called for all non- <B>NULL</B> values, there are still some
non- <B>NULL</B> values with associated destructors, then the process
-is repeated. The <B>Pthreads-w32</B> implementation stops the process after
-<B>PTHREAD_DESTRUCTOR_ITERATIONS</B> iterations, even if some non-
-<B>NULL</B> values with associated descriptors remain. Other
-implementations may loop indefinitely.
-</P>
+is repeated.</P>
<P><B>pthread_key_delete</B> deallocates a TSD key. It does not check
whether non- <B>NULL</B> 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 <I>pointer</I> instead.
<P><B>pthread_getspecific</B> returns the value currently associated
with <I>key</I> in the calling thread.
</P>
+<P>The routines <B>pthread_setspecific</B>, <B>pthread_getspecific</B>,
+and <B>pthread_key_delete</B> can be called from <I>destr_function</I>
+targeting any valid key including the key on which <I>destr_function</I>
+is currently operating. If <B>pthread_getspecific</B> is called on
+the key whose thread specific data is being destroyed, the value NULL
+is returned, unless <B>pthread_setspecific</B> was called previously
+on that key from within <I>destr_function</I> to set the value to
+non-NULL. For some implementations the effect of calling
+<B>pthread_setspecific</B> from within <I>destr_function</I> can be
+either memory leakage or infinite loops if <I>destr_function</I> has
+already been called at least <B>PTHREAD_DESTRUCTOR_ITERATIONS</B>
+times.</P>
+<P STYLE="font-weight: medium"><B>Pthreads-w32</B> stops running key
+<I>destr_function</I> routines after <B>PTHREAD_DESTRUCTOR_ITERATIONS</B>
+iterations, even if some non- <B>NULL</B> values with associated
+descriptors remain. If memory is allocated and associated with a key
+from within <I>destr_function</I>, that memory may not be reclaimed
+because that key's <I>destr_function</I>, may not run again.</P>
<H2><A HREF="#toc3" NAME="sect3">Return Value</A></H2>
<P><B>pthread_key_create</B>, <B>pthread_key_delete</B>, and
<B>pthread_setspecific</B> return 0 on success and a non-zero error
@@ -105,7 +119,7 @@ error:
<DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"><B>EAGAIN</B>
</DT></DL>
</DL>
-<BLOCKQUOTE STYLE="margin-left: 3cm">
+<BLOCKQUOTE STYLE="margin-left: 5cm">
<B>PTHREAD_KEYS_MAX</B> keys are already allocated
</BLOCKQUOTE>
<DL>
@@ -113,7 +127,7 @@ error:
<DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"><B>ENOMEM</B>
</DT></DL>
</DL>
-<BLOCKQUOTE STYLE="margin-left: 3cm">
+<BLOCKQUOTE STYLE="margin-left: 5cm">
Insufficient memory to allocate the key.
</BLOCKQUOTE>
<P><B>pthread_key_delete</B> and <B>pthread_setspecific</B> return
@@ -171,8 +185,8 @@ static void buffer_destroy(void * buf)
free(buf);
}</PRE>
<HR>
-<BLOCKQUOTE STYLE="margin-left: 0cm"><A NAME="toc"></A><B>Table of
-Contents</B></BLOCKQUOTE>
+<BLOCKQUOTE STYLE="margin-left: 0cm; margin-right: 0cm"><A NAME="toc"></A>
+<B>Table of Contents</B></BLOCKQUOTE>
<UL>
<LI><BLOCKQUOTE STYLE="margin-bottom: 0cm"><A HREF="#sect0" NAME="toc0">Name</A>
</BLOCKQUOTE>
@@ -194,4 +208,4 @@ Contents</B></BLOCKQUOTE>
</BLOCKQUOTE>
</UL>
</BODY>
-</HTML>
+</HTML> \ 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);
}