diff options
| author | rpj <rpj> | 2005-05-09 08:31:31 +0000 | 
|---|---|---|
| committer | rpj <rpj> | 2005-05-09 08:31:31 +0000 | 
| commit | 6961e1741a9bdcff4b075859acc15e56031889a3 (patch) | |
| tree | a31b393d3d9e3c2ec95b5c5d24ab797569a027d2 | |
| parent | 7395b1431d5e2160682de273b46252c747ccbf36 (diff) | |
''
| -rw-r--r-- | manual/pthread_key_create.html | 42 | ||||
| -rw-r--r-- | 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 @@  	<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);      } | 
