Home | History | Annotate | Download | only in pthreads-win32
      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 (at) 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 
     48 static DWORD
     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
    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
    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