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