diff options
| author | rpj <rpj> | 2005-05-09 08:32:18 +0000 | 
|---|---|---|
| committer | rpj <rpj> | 2005-05-09 08:32:18 +0000 | 
| commit | 99aebd430a3a4f037cc10d14751afcb99fe0365f (patch) | |
| tree | 2011c56fda99f2b89d43cd5db6fa442dd6c159cf /ptw32_callUserDestroyRoutines.c | |
| parent | ac8e3d247fa03af61b5411f92508481e7c3f49f8 (diff) | |
''
Diffstat (limited to 'ptw32_callUserDestroyRoutines.c')
| -rw-r--r-- | ptw32_callUserDestroyRoutines.c | 184 | 
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);      } | 
