1 /*
2 * ptw32_callUserDestroyRoutines.c
3 *
4 * Description:
5 * This translation unit implements routines which are private to
6 * the implementation and may be used throughout it.
7 *
8 * --------------------------------------------------------------------------
9 *
10 * Pthreads-win32 - POSIX Threads Library for Win32
11 * Copyright(C) 1998 John E. Bossom
12 * Copyright(C) 1999,2005 Pthreads-win32 contributors
13 *
14 * Contact Email: rpj@callisto.canberra.edu.au
15 *
16 * The current list of contributors is contained
17 * in the file CONTRIBUTORS included with the source
18 * code distribution. The list can also be seen at the
19 * following World Wide Web location:
20 * http://sources.redhat.com/pthreads-win32/contributors.html
21 *
22 * This library is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU Lesser General Public
24 * License as published by the Free Software Foundation; either
25 * version 2 of the License, or (at your option) any later version.
26 *
27 * This library is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 * Lesser General Public License for more details.
31 *
32 * You should have received a copy of the GNU Lesser General Public
33 * License along with this library in the file COPYING.LIB;
34 * if not, write to the Free Software Foundation, Inc.,
35 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
36 */
37
38 #include "pthread.h"
39 #include "implement.h"
40
41 #if defined(__CLEANUP_CXX)
42 # if defined(_MSC_VER)
43 # include <eh.h>
44 # elif defined(__WATCOMC__)
45 # include <eh.h>
46 # include <exceptio.h>
47 # else
48 # if defined(__GNUC__) && __GNUC__ < 3
49 # include <new.h>
50 # else
51 # include <new>
52 using
53 std::terminate;
54 # endif
55 # endif
56 #endif
57
58 void
ptw32_callUserDestroyRoutines(pthread_t thread)59 ptw32_callUserDestroyRoutines (pthread_t thread)
60 /*
61 * -------------------------------------------------------------------
62 * DOCPRIVATE
63 *
64 * This the routine runs through all thread keys and calls
65 * the destroy routines on the user's data for the current thread.
66 * It simulates the behaviour of POSIX Threads.
67 *
68 * PARAMETERS
69 * thread
70 * an instance of pthread_t
71 *
72 * RETURNS
73 * N/A
74 * -------------------------------------------------------------------
75 */
76 {
77 ThreadKeyAssoc * assoc;
78
79 if (thread.p != NULL)
80 {
81 ptw32_mcs_local_node_t threadLock;
82 ptw32_mcs_local_node_t keyLock;
83 int assocsRemaining;
84 int iterations = 0;
85 ptw32_thread_t * sp = (ptw32_thread_t *) thread.p;
86
87 /*
88 * Run through all Thread<-->Key associations
89 * for the current thread.
90 *
91 * Do this process at most PTHREAD_DESTRUCTOR_ITERATIONS times.
92 */
93 do
94 {
95 assocsRemaining = 0;
96 iterations++;
97
98 ptw32_mcs_lock_acquire(&(sp->threadLock), &threadLock);
99 /*
100 * The pointer to the next assoc is stored in the thread struct so that
101 * the assoc destructor in pthread_key_delete can adjust it
102 * if it deletes this assoc. This can happen if we fail to acquire
103 * both locks below, and are forced to release all of our locks,
104 * leaving open the opportunity for pthread_key_delete to get in
105 * before us.
106 */
107 sp->nextAssoc = sp->keys;
108 ptw32_mcs_lock_release(&threadLock);
109
110 for (;;)
111 {
112 void * value;
113 pthread_key_t k;
114 void (*destructor) (void *);
115
116 /*
117 * First we need to serialise with pthread_key_delete by locking
118 * both assoc guards, but in the reverse order to our convention,
119 * so we must be careful to avoid deadlock.
120 */
121 ptw32_mcs_lock_acquire(&(sp->threadLock), &threadLock);
122
123 if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL)
124 {
125 /* Finished */
126 ptw32_mcs_lock_release(&threadLock);
127 break;
128 }
129 else
130 {
131 /*
132 * assoc->key must be valid because assoc can't change or be
133 * removed from our chain while we hold at least one lock. If
134 * the assoc was on our key chain then the key has not been
135 * deleted yet.
136 *
137 * Now try to acquire the second lock without deadlocking.
138 * If we fail, we need to relinquish the first lock and the
139 * processor and then try to acquire them all again.
140 */
141 if (ptw32_mcs_lock_try_acquire(&(assoc->key->keyLock), &keyLock) == EBUSY)
142 {
143 ptw32_mcs_lock_release(&threadLock);
144 Sleep(0);
145 /*
146 * Go around again.
147 * If pthread_key_delete has removed this assoc in the meantime,
148 * sp->nextAssoc will point to a new assoc.
149 */
150 continue;
151 }
152 }
153
154 /* We now hold both locks */
155
156 sp->nextAssoc = assoc->nextKey;
157
158 /*
159 * Key still active; pthread_key_delete
160 * will block on these same mutexes before
161 * it can release actual key; therefore,
162 * key is valid and we can call the destroy
163 * routine;
164 */
165 k = assoc->key;
166 destructor = k->destructor;
167 value = TlsGetValue(k->key);
168 TlsSetValue (k->key, NULL);
169
170 // Every assoc->key exists and has a destructor
171 if (value != NULL && iterations <= PTHREAD_DESTRUCTOR_ITERATIONS)
172 {
173 /*
174 * Unlock both locks before the destructor runs.
175 * POSIX says pthread_key_delete can be run from destructors,
176 * and that probably includes with this key as target.
177 * pthread_setspecific can also be run from destructors and
178 * also needs to be able to access the assocs.
179 */
180 ptw32_mcs_lock_release(&threadLock);
181 ptw32_mcs_lock_release(&keyLock);
182
183 assocsRemaining++;
184
185 #if defined(__cplusplus)
186
187 try
188 {
189 /*
190 * Run the caller's cleanup routine.
191 */
192 destructor (value);
193 }
194 catch (...)
195 {
196 /*
197 * A system unexpected exception has occurred
198 * running the user's destructor.
199 * We get control back within this block in case
200 * the application has set up it's own terminate
201 * handler. Since we are leaving the thread we
202 * should not get any internal pthreads
203 * exceptions.
204 */
205 terminate ();
206 }
207
208 #else /* __cplusplus */
209
210 /*
211 * Run the caller's cleanup routine.
212 */
213 destructor (value);
214
215 #endif /* __cplusplus */
216
217 }
218 else
219 {
220 /*
221 * Remove association from both the key and thread chains
222 * and reclaim it's memory resources.
223 */
224 ptw32_tkAssocDestroy (assoc);
225 ptw32_mcs_lock_release(&threadLock);
226 ptw32_mcs_lock_release(&keyLock);
227 }
228 }
229 }
230 while (assocsRemaining);
231 }
232 } /* ptw32_callUserDestroyRoutines */
233