xref: /relibc/pthreads-emb/pte_callUserDestroyRoutines.c (revision a12978ccca4c576f02971f5cfc2cbefe23e4daba)
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