123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- /*
- * pte_callUserDestroyRoutines.c
- *
- * Description:
- * This translation unit implements routines which are private to
- * the implementation and may be used throughout it.
- *
- * --------------------------------------------------------------------------
- *
- * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
- * Copyright(C) 2008 Jason Schmidlapp
- *
- * Contact Email: [email protected]
- *
- *
- * Based upon Pthreads-win32 - POSIX Threads Library for Win32
- * Copyright(C) 1998 John E. Bossom
- * Copyright(C) 1999,2005 Pthreads-win32 contributors
- *
- * Contact Email: [email protected]
- *
- * The original list of contributors to the Pthreads-win32 project
- * is contained in the file CONTRIBUTORS.ptw32 included with the
- * source code distribution. The list can also be seen at the
- * following World Wide Web location:
- * http://sources.redhat.com/pthreads-win32/contributors.html
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library in the file COPYING.LIB;
- * if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include "pthread.h"
- #include "implement.h"
- #include <pte_osal.h>
- #ifdef __cplusplus
- #include <exception>
- using std::terminate;
- #endif
- void
- pte_callUserDestroyRoutines (pthread_t thread)
- /*
- * -------------------------------------------------------------------
- * DOCPRIVATE
- *
- * This the routine runs through all thread keys and calls
- * the destroy routines on the user's data for the current thread.
- * It simulates the behaviour of POSIX Threads.
- *
- * PARAMETERS
- * thread
- * an instance of pthread_t
- *
- * RETURNS
- * N/A
- * -------------------------------------------------------------------
- */
- {
- ThreadKeyAssoc * assoc;
- if (thread != NULL)
- {
- int assocsRemaining;
- int iterations = 0;
- pte_thread_t * sp = (pte_thread_t *) thread;
- /*
- * Run through all Thread<-->Key associations
- * for the current thread.
- *
- * Do this process at most PTHREAD_DESTRUCTOR_ITERATIONS times.
- */
- do
- {
- assocsRemaining = 0;
- iterations++;
- (void) pthread_mutex_lock(&(sp->threadLock));
- /*
- * 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 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 *);
- /*
- * 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.
- */
- (void) pthread_mutex_lock(&(sp->threadLock));
- if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL)
- {
- /* Finished */
- pthread_mutex_unlock(&(sp->threadLock));
- break;
- }
- else
- {
- /*
- * 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.
- */
- if (pthread_mutex_trylock(&(assoc->key->keyLock)) == EBUSY)
- {
- pthread_mutex_unlock(&(sp->threadLock));
- pte_osThreadSleep(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;
- /*
- * 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 = pte_osTlsGetValue(k->key);
- pte_osTlsSetValue (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++;
- #ifdef __cplusplus
- 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 */
- }
- else
- {
- /*
- * Remove association from both the key and thread chains
- * and reclaim it's memory resources.
- */
- pte_tkAssocDestroy (assoc);
- (void) pthread_mutex_unlock(&(sp->threadLock));
- (void) pthread_mutex_unlock(&(k->keyLock));
- }
- }
- }
- while (assocsRemaining);
- }
- } /* pte_callUserDestroyRoutines */
|