1062c5bc4SJason Schmidlapp /*
2062c5bc4SJason Schmidlapp * pte_callUserDestroyRoutines.c
3062c5bc4SJason Schmidlapp *
4062c5bc4SJason Schmidlapp * Description:
5062c5bc4SJason Schmidlapp * This translation unit implements routines which are private to
6062c5bc4SJason Schmidlapp * the implementation and may be used throughout it.
7062c5bc4SJason Schmidlapp *
8062c5bc4SJason Schmidlapp * --------------------------------------------------------------------------
9062c5bc4SJason Schmidlapp *
10062c5bc4SJason Schmidlapp * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
11062c5bc4SJason Schmidlapp * Copyright(C) 2008 Jason Schmidlapp
12062c5bc4SJason Schmidlapp *
13062c5bc4SJason Schmidlapp * Contact Email: jschmidlapp@users.sourceforge.net
14062c5bc4SJason Schmidlapp *
15062c5bc4SJason Schmidlapp *
16062c5bc4SJason Schmidlapp * Based upon Pthreads-win32 - POSIX Threads Library for Win32
17062c5bc4SJason Schmidlapp * Copyright(C) 1998 John E. Bossom
18062c5bc4SJason Schmidlapp * Copyright(C) 1999,2005 Pthreads-win32 contributors
19062c5bc4SJason Schmidlapp *
20062c5bc4SJason Schmidlapp * Contact Email: rpj@callisto.canberra.edu.au
21062c5bc4SJason Schmidlapp *
22062c5bc4SJason Schmidlapp * The original list of contributors to the Pthreads-win32 project
23062c5bc4SJason Schmidlapp * is contained in the file CONTRIBUTORS.ptw32 included with the
24062c5bc4SJason Schmidlapp * source code distribution. The list can also be seen at the
25062c5bc4SJason Schmidlapp * following World Wide Web location:
26062c5bc4SJason Schmidlapp * http://sources.redhat.com/pthreads-win32/contributors.html
27062c5bc4SJason Schmidlapp *
28062c5bc4SJason Schmidlapp * This library is free software; you can redistribute it and/or
29062c5bc4SJason Schmidlapp * modify it under the terms of the GNU Lesser General Public
30062c5bc4SJason Schmidlapp * License as published by the Free Software Foundation; either
31062c5bc4SJason Schmidlapp * version 2 of the License, or (at your option) any later version.
32062c5bc4SJason Schmidlapp *
33062c5bc4SJason Schmidlapp * This library is distributed in the hope that it will be useful,
34062c5bc4SJason Schmidlapp * but WITHOUT ANY WARRANTY; without even the implied warranty of
35062c5bc4SJason Schmidlapp * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36062c5bc4SJason Schmidlapp * Lesser General Public License for more details.
37062c5bc4SJason Schmidlapp *
38062c5bc4SJason Schmidlapp * You should have received a copy of the GNU Lesser General Public
39062c5bc4SJason Schmidlapp * License along with this library in the file COPYING.LIB;
40062c5bc4SJason Schmidlapp * if not, write to the Free Software Foundation, Inc.,
41062c5bc4SJason Schmidlapp * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
42062c5bc4SJason Schmidlapp */
43062c5bc4SJason Schmidlapp
44062c5bc4SJason Schmidlapp #include <stdio.h>
45062c5bc4SJason Schmidlapp #include <stdlib.h>
46062c5bc4SJason Schmidlapp
47062c5bc4SJason Schmidlapp #include "pthread.h"
48062c5bc4SJason Schmidlapp #include "implement.h"
49062c5bc4SJason Schmidlapp
50062c5bc4SJason Schmidlapp #include <pte_osal.h>
51062c5bc4SJason Schmidlapp
52062c5bc4SJason Schmidlapp #ifdef __cplusplus
53062c5bc4SJason Schmidlapp #include <exception>
54062c5bc4SJason Schmidlapp using std::terminate;
55062c5bc4SJason Schmidlapp #endif
56062c5bc4SJason Schmidlapp
57062c5bc4SJason Schmidlapp void
pte_callUserDestroyRoutines(pthread_t thread)58062c5bc4SJason Schmidlapp pte_callUserDestroyRoutines (pthread_t thread)
59062c5bc4SJason Schmidlapp /*
60062c5bc4SJason Schmidlapp * -------------------------------------------------------------------
61062c5bc4SJason Schmidlapp * DOCPRIVATE
62062c5bc4SJason Schmidlapp *
63062c5bc4SJason Schmidlapp * This the routine runs through all thread keys and calls
64062c5bc4SJason Schmidlapp * the destroy routines on the user's data for the current thread.
65062c5bc4SJason Schmidlapp * It simulates the behaviour of POSIX Threads.
66062c5bc4SJason Schmidlapp *
67062c5bc4SJason Schmidlapp * PARAMETERS
68062c5bc4SJason Schmidlapp * thread
69062c5bc4SJason Schmidlapp * an instance of pthread_t
70062c5bc4SJason Schmidlapp *
71062c5bc4SJason Schmidlapp * RETURNS
72062c5bc4SJason Schmidlapp * N/A
73062c5bc4SJason Schmidlapp * -------------------------------------------------------------------
74062c5bc4SJason Schmidlapp */
75062c5bc4SJason Schmidlapp {
76062c5bc4SJason Schmidlapp ThreadKeyAssoc * assoc;
77062c5bc4SJason Schmidlapp
78*a12978ccSJeremy Soller if (thread != NULL)
79062c5bc4SJason Schmidlapp {
80062c5bc4SJason Schmidlapp int assocsRemaining;
81062c5bc4SJason Schmidlapp int iterations = 0;
82*a12978ccSJeremy Soller pte_thread_t * sp = (pte_thread_t *) thread;
83062c5bc4SJason Schmidlapp
84062c5bc4SJason Schmidlapp /*
85062c5bc4SJason Schmidlapp * Run through all Thread<-->Key associations
86062c5bc4SJason Schmidlapp * for the current thread.
87062c5bc4SJason Schmidlapp *
88062c5bc4SJason Schmidlapp * Do this process at most PTHREAD_DESTRUCTOR_ITERATIONS times.
89062c5bc4SJason Schmidlapp */
90062c5bc4SJason Schmidlapp do
91062c5bc4SJason Schmidlapp {
92062c5bc4SJason Schmidlapp assocsRemaining = 0;
93062c5bc4SJason Schmidlapp iterations++;
94062c5bc4SJason Schmidlapp
95062c5bc4SJason Schmidlapp (void) pthread_mutex_lock(&(sp->threadLock));
96062c5bc4SJason Schmidlapp /*
97062c5bc4SJason Schmidlapp * The pointer to the next assoc is stored in the thread struct so that
98062c5bc4SJason Schmidlapp * the assoc destructor in pthread_key_delete can adjust it
99062c5bc4SJason Schmidlapp * if it deletes this assoc. This can happen if we fail to acquire
100062c5bc4SJason Schmidlapp * both locks below, and are forced to release all of our locks,
101062c5bc4SJason Schmidlapp * leaving open the opportunity for pthread_key_delete to get in
102062c5bc4SJason Schmidlapp * before us.
103062c5bc4SJason Schmidlapp */
104062c5bc4SJason Schmidlapp sp->nextAssoc = sp->keys;
105062c5bc4SJason Schmidlapp (void) pthread_mutex_unlock(&(sp->threadLock));
106062c5bc4SJason Schmidlapp
107062c5bc4SJason Schmidlapp for (;;)
108062c5bc4SJason Schmidlapp {
109062c5bc4SJason Schmidlapp void * value;
110062c5bc4SJason Schmidlapp pthread_key_t k;
111062c5bc4SJason Schmidlapp void (*destructor) (void *);
112062c5bc4SJason Schmidlapp
113062c5bc4SJason Schmidlapp /*
114062c5bc4SJason Schmidlapp * First we need to serialise with pthread_key_delete by locking
115062c5bc4SJason Schmidlapp * both assoc guards, but in the reverse order to our convention,
116062c5bc4SJason Schmidlapp * so we must be careful to avoid deadlock.
117062c5bc4SJason Schmidlapp */
118062c5bc4SJason Schmidlapp (void) pthread_mutex_lock(&(sp->threadLock));
119062c5bc4SJason Schmidlapp
120062c5bc4SJason Schmidlapp if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL)
121062c5bc4SJason Schmidlapp {
122062c5bc4SJason Schmidlapp /* Finished */
123062c5bc4SJason Schmidlapp pthread_mutex_unlock(&(sp->threadLock));
124062c5bc4SJason Schmidlapp break;
125062c5bc4SJason Schmidlapp }
126062c5bc4SJason Schmidlapp else
127062c5bc4SJason Schmidlapp {
128062c5bc4SJason Schmidlapp /*
129062c5bc4SJason Schmidlapp * assoc->key must be valid because assoc can't change or be
130062c5bc4SJason Schmidlapp * removed from our chain while we hold at least one lock. If
131062c5bc4SJason Schmidlapp * the assoc was on our key chain then the key has not been
132062c5bc4SJason Schmidlapp * deleted yet.
133062c5bc4SJason Schmidlapp *
134062c5bc4SJason Schmidlapp * Now try to acquire the second lock without deadlocking.
135062c5bc4SJason Schmidlapp * If we fail, we need to relinquish the first lock and the
136062c5bc4SJason Schmidlapp * processor and then try to acquire them all again.
137062c5bc4SJason Schmidlapp */
138062c5bc4SJason Schmidlapp if (pthread_mutex_trylock(&(assoc->key->keyLock)) == EBUSY)
139062c5bc4SJason Schmidlapp {
140062c5bc4SJason Schmidlapp pthread_mutex_unlock(&(sp->threadLock));
141062c5bc4SJason Schmidlapp pte_osThreadSleep(1); // Ugly but necessary to avoid priority effects.
142062c5bc4SJason Schmidlapp /*
143062c5bc4SJason Schmidlapp * Go around again.
144062c5bc4SJason Schmidlapp * If pthread_key_delete has removed this assoc in the meantime,
145062c5bc4SJason Schmidlapp * sp->nextAssoc will point to a new assoc.
146062c5bc4SJason Schmidlapp */
147062c5bc4SJason Schmidlapp continue;
148062c5bc4SJason Schmidlapp }
149062c5bc4SJason Schmidlapp }
150062c5bc4SJason Schmidlapp
151062c5bc4SJason Schmidlapp /* We now hold both locks */
152062c5bc4SJason Schmidlapp
153062c5bc4SJason Schmidlapp sp->nextAssoc = assoc->nextKey;
154062c5bc4SJason Schmidlapp
155062c5bc4SJason Schmidlapp /*
156062c5bc4SJason Schmidlapp * Key still active; pthread_key_delete
157062c5bc4SJason Schmidlapp * will block on these same mutexes before
158062c5bc4SJason Schmidlapp * it can release actual key; therefore,
159062c5bc4SJason Schmidlapp * key is valid and we can call the destroy
160062c5bc4SJason Schmidlapp * routine;
161062c5bc4SJason Schmidlapp */
162062c5bc4SJason Schmidlapp k = assoc->key;
163062c5bc4SJason Schmidlapp destructor = k->destructor;
164062c5bc4SJason Schmidlapp value = pte_osTlsGetValue(k->key);
165062c5bc4SJason Schmidlapp pte_osTlsSetValue (k->key, NULL);
166062c5bc4SJason Schmidlapp
167062c5bc4SJason Schmidlapp // Every assoc->key exists and has a destructor
168062c5bc4SJason Schmidlapp if (value != NULL && iterations <= PTHREAD_DESTRUCTOR_ITERATIONS)
169062c5bc4SJason Schmidlapp {
170062c5bc4SJason Schmidlapp /*
171062c5bc4SJason Schmidlapp * Unlock both locks before the destructor runs.
172062c5bc4SJason Schmidlapp * POSIX says pthread_key_delete can be run from destructors,
173062c5bc4SJason Schmidlapp * and that probably includes with this key as target.
174062c5bc4SJason Schmidlapp * pthread_setspecific can also be run from destructors and
175062c5bc4SJason Schmidlapp * also needs to be able to access the assocs.
176062c5bc4SJason Schmidlapp */
177062c5bc4SJason Schmidlapp (void) pthread_mutex_unlock(&(sp->threadLock));
178062c5bc4SJason Schmidlapp (void) pthread_mutex_unlock(&(k->keyLock));
179062c5bc4SJason Schmidlapp
180062c5bc4SJason Schmidlapp assocsRemaining++;
181062c5bc4SJason Schmidlapp
182062c5bc4SJason Schmidlapp #ifdef __cplusplus
183062c5bc4SJason Schmidlapp
184062c5bc4SJason Schmidlapp try
185062c5bc4SJason Schmidlapp {
186062c5bc4SJason Schmidlapp /*
187062c5bc4SJason Schmidlapp * Run the caller's cleanup routine.
188062c5bc4SJason Schmidlapp */
189062c5bc4SJason Schmidlapp destructor (value);
190062c5bc4SJason Schmidlapp }
191062c5bc4SJason Schmidlapp catch (...)
192062c5bc4SJason Schmidlapp {
193062c5bc4SJason Schmidlapp /*
194062c5bc4SJason Schmidlapp * A system unexpected exception has occurred
195062c5bc4SJason Schmidlapp * running the user's destructor.
196062c5bc4SJason Schmidlapp * We get control back within this block in case
197062c5bc4SJason Schmidlapp * the application has set up it's own terminate
198062c5bc4SJason Schmidlapp * handler. Since we are leaving the thread we
199062c5bc4SJason Schmidlapp * should not get any internal pthreads
200062c5bc4SJason Schmidlapp * exceptions.
201062c5bc4SJason Schmidlapp */
202062c5bc4SJason Schmidlapp terminate ();
203062c5bc4SJason Schmidlapp }
204062c5bc4SJason Schmidlapp
205062c5bc4SJason Schmidlapp #else /* __cplusplus */
206062c5bc4SJason Schmidlapp
207062c5bc4SJason Schmidlapp /*
208062c5bc4SJason Schmidlapp * Run the caller's cleanup routine.
209062c5bc4SJason Schmidlapp */
210062c5bc4SJason Schmidlapp destructor (value);
211062c5bc4SJason Schmidlapp
212062c5bc4SJason Schmidlapp #endif /* __cplusplus */
213062c5bc4SJason Schmidlapp
214062c5bc4SJason Schmidlapp }
215062c5bc4SJason Schmidlapp else
216062c5bc4SJason Schmidlapp {
217062c5bc4SJason Schmidlapp /*
218062c5bc4SJason Schmidlapp * Remove association from both the key and thread chains
219062c5bc4SJason Schmidlapp * and reclaim it's memory resources.
220062c5bc4SJason Schmidlapp */
221062c5bc4SJason Schmidlapp pte_tkAssocDestroy (assoc);
222062c5bc4SJason Schmidlapp (void) pthread_mutex_unlock(&(sp->threadLock));
223062c5bc4SJason Schmidlapp (void) pthread_mutex_unlock(&(k->keyLock));
224062c5bc4SJason Schmidlapp }
225062c5bc4SJason Schmidlapp }
226062c5bc4SJason Schmidlapp }
227062c5bc4SJason Schmidlapp while (assocsRemaining);
228062c5bc4SJason Schmidlapp }
229062c5bc4SJason Schmidlapp } /* pte_callUserDestroyRoutines */
230