1 /*
2 * ptw32_threadStart.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 #include <stdio.h>
41
42 #if defined(__CLEANUP_C)
43 # include <setjmp.h>
44 #endif
45
46 #if defined(__CLEANUP_SEH)
47
48 static DWORD
ExceptionFilter(EXCEPTION_POINTERS * ep,DWORD * ei)49 ExceptionFilter (EXCEPTION_POINTERS * ep, DWORD * ei)
50 {
51 switch (ep->ExceptionRecord->ExceptionCode)
52 {
53 case EXCEPTION_PTW32_SERVICES:
54 {
55 DWORD param;
56 DWORD numParams = ep->ExceptionRecord->NumberParameters;
57
58 numParams = (numParams > 3) ? 3 : numParams;
59
60 for (param = 0; param < numParams; param++)
61 {
62 ei[param] = ep->ExceptionRecord->ExceptionInformation[param];
63 }
64
65 return EXCEPTION_EXECUTE_HANDLER;
66 break;
67 }
68 default:
69 {
70 /*
71 * A system unexpected exception has occurred running the user's
72 * routine. We need to cleanup before letting the exception
73 * out of thread scope.
74 */
75 pthread_t self = pthread_self ();
76
77 ptw32_callUserDestroyRoutines (self);
78
79 return EXCEPTION_CONTINUE_SEARCH;
80 break;
81 }
82 }
83 }
84
85 #elif defined(__CLEANUP_CXX)
86
87 #if defined(_MSC_VER)
88 # include <eh.h>
89 #elif defined(__WATCOMC__)
90 # include <eh.h>
91 # include <exceptio.h>
92 typedef terminate_handler
93 terminate_function;
94 #else
95 # if defined(__GNUC__) && __GNUC__ < 3
96 # include <new.h>
97 # else
98 # include <new>
99 using
100 std::terminate_handler;
101 using
102 std::terminate;
103 using
104 std::set_terminate;
105 # endif
106 typedef terminate_handler
107 terminate_function;
108 #endif
109
110 static terminate_function
111 ptw32_oldTerminate;
112
113 void
ptw32_terminate()114 ptw32_terminate ()
115 {
116 set_terminate (ptw32_oldTerminate);
117 (void) pthread_win32_thread_detach_np ();
118 terminate ();
119 }
120
121 #endif
122
123 #if ! (defined(__MINGW64__) || defined(__MINGW32__)) || (defined (__MSVCRT__) && ! defined (__DMC__))
124 unsigned
125 __stdcall
126 #else
127 void
128 #endif
ptw32_threadStart(void * vthreadParms)129 ptw32_threadStart (void *vthreadParms)
130 {
131 ThreadParms * threadParms = (ThreadParms *) vthreadParms;
132 pthread_t self;
133 ptw32_thread_t * sp;
134 void * (PTW32_CDECL *start) (void *);
135 void * arg;
136
137 #if defined(__CLEANUP_SEH)
138 DWORD
139 ei[] = { 0, 0, 0 };
140 #endif
141
142 #if defined(__CLEANUP_C)
143 int setjmp_rc;
144 #endif
145
146 ptw32_mcs_local_node_t stateLock;
147 void * status = (void *) 0;
148
149 self = threadParms->tid;
150 sp = (ptw32_thread_t *) self.p;
151 start = threadParms->start;
152 arg = threadParms->arg;
153
154 free (threadParms);
155
156 #if (defined(__MINGW64__) || defined(__MINGW32__)) && ! defined (__MSVCRT__)
157 /*
158 * beginthread does not return the thread id and is running
159 * before it returns us the thread handle, and so we do it here.
160 */
161 sp->thread = GetCurrentThreadId ();
162 /*
163 * Here we're using stateLock as a general-purpose lock
164 * to make the new thread wait until the creating thread
165 * has the new handle.
166 */
167 ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);
168 pthread_setspecific (ptw32_selfThreadKey, sp);
169 #else
170 pthread_setspecific (ptw32_selfThreadKey, sp);
171 ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock);
172 #endif
173
174 sp->state = PThreadStateRunning;
175 ptw32_mcs_lock_release (&stateLock);
176
177 #if defined(__CLEANUP_SEH)
178
179 __try
180 {
181 /*
182 * Run the caller's routine;
183 */
184 status = sp->exitStatus = (*start) (arg);
185 sp->state = PThreadStateExiting;
186
187 #if defined(_UWIN)
188 if (--pthread_count <= 0)
189 exit (0);
190 #endif
191
192 }
193 __except (ExceptionFilter (GetExceptionInformation (), ei))
194 {
195 switch (ei[0])
196 {
197 case PTW32_EPS_CANCEL:
198 status = sp->exitStatus = PTHREAD_CANCELED;
199 #if defined(_UWIN)
200 if (--pthread_count <= 0)
201 exit (0);
202 #endif
203 break;
204 case PTW32_EPS_EXIT:
205 status = sp->exitStatus;
206 break;
207 default:
208 status = sp->exitStatus = PTHREAD_CANCELED;
209 break;
210 }
211 }
212
213 #else /* __CLEANUP_SEH */
214
215 #if defined(__CLEANUP_C)
216
217 setjmp_rc = setjmp (sp->start_mark);
218
219 if (0 == setjmp_rc)
220 {
221
222 /*
223 * Run the caller's routine;
224 */
225 status = sp->exitStatus = (*start) (arg);
226 sp->state = PThreadStateExiting;
227 }
228 else
229 {
230 switch (setjmp_rc)
231 {
232 case PTW32_EPS_CANCEL:
233 status = sp->exitStatus = PTHREAD_CANCELED;
234 break;
235 case PTW32_EPS_EXIT:
236 status = sp->exitStatus;
237 break;
238 default:
239 status = sp->exitStatus = PTHREAD_CANCELED;
240 break;
241 }
242 }
243
244 #else /* __CLEANUP_C */
245
246 #if defined(__CLEANUP_CXX)
247
248 ptw32_oldTerminate = set_terminate (&ptw32_terminate);
249
250 try
251 {
252 /*
253 * Run the caller's routine in a nested try block so that we
254 * can run the user's terminate function, which may call
255 * pthread_exit() or be canceled.
256 */
257 try
258 {
259 status = sp->exitStatus = (*start) (arg);
260 sp->state = PThreadStateExiting;
261 }
262 catch (ptw32_exception &)
263 {
264 /*
265 * Pass these through to the outer block.
266 */
267 throw;
268 }
269 catch (...)
270 {
271 /*
272 * We want to run the user's terminate function if supplied.
273 * That function may call pthread_exit() or be canceled, which will
274 * be handled by the outer try block.
275 *
276 * ptw32_terminate() will be called if there is no user
277 * supplied function.
278 */
279 terminate_function
280 term_func = set_terminate (0);
281 set_terminate (term_func);
282
283 if (term_func != 0)
284 {
285 term_func ();
286 }
287 throw;
288 }
289 }
290 catch (ptw32_exception_cancel &)
291 {
292 /*
293 * Thread was canceled.
294 */
295 status = sp->exitStatus = PTHREAD_CANCELED;
296 }
297 catch (ptw32_exception_exit &)
298 {
299 /*
300 * Thread was exited via pthread_exit().
301 */
302 status = sp->exitStatus;
303 }
304 catch (...)
305 {
306 /*
307 * A system unexpected exception has occurred running the user's
308 * terminate routine. We get control back within this block
309 * and exit with a substitute status. If the thread was not
310 * cancelled then this indicates the unhandled exception.
311 */
312 status = sp->exitStatus = PTHREAD_CANCELED;
313 }
314
315 (void) set_terminate (ptw32_oldTerminate);
316
317 #else
318
319 #error ERROR [__FILE__, line __LINE__]: Cleanup type undefined.
320
321 #endif /* __CLEANUP_CXX */
322 #endif /* __CLEANUP_C */
323 #endif /* __CLEANUP_SEH */
324
325 #if defined(PTW32_STATIC_LIB)
326 /*
327 * We need to cleanup the pthread now if we have
328 * been statically linked, in which case the cleanup
329 * in dllMain won't get done. Joinable threads will
330 * only be partially cleaned up and must be fully cleaned
331 * up by pthread_join() or pthread_detach().
332 *
333 * Note: if this library has been statically linked,
334 * implicitly created pthreads (those created
335 * for Win32 threads which have called pthreads routines)
336 * must be cleaned up explicitly by the application
337 * (by calling pthread_win32_thread_detach_np()).
338 * For the dll, dllMain will do the cleanup automatically.
339 */
340 (void) pthread_win32_thread_detach_np ();
341 #endif
342
343 #if ! (defined(__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__)
344 _endthreadex ((unsigned)(size_t) status);
345 #else
346 _endthread ();
347 #endif
348
349 /*
350 * Never reached.
351 */
352
353 #if ! (defined(__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__)
354 return (unsigned)(size_t) status;
355 #endif
356
357 } /* ptw32_threadStart */
358