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