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 *      59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
48static DWORD
49ExceptionFilter (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>
92typedef terminate_handler
93  terminate_function;
94#else
95# if defined(__GNUC__) && __GNUC__ < 3
96#   include <new.h>
97# else
98#   include <new>
99using
100  std::terminate_handler;
101using
102  std::terminate;
103using
104  std::set_terminate;
105# endif
106typedef terminate_handler
107  terminate_function;
108#endif
109
110static terminate_function
111  ptw32_oldTerminate;
112
113void
114ptw32_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__))
124unsigned
125  __stdcall
126#else
127void
128#endif
129ptw32_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