diff --git a/3rdparty/w32pthreads/cleanup.c b/3rdparty/w32pthreads/cleanup.c index 9cbf3cfdb8..4b88d011aa 100644 --- a/3rdparty/w32pthreads/cleanup.c +++ b/3rdparty/w32pthreads/cleanup.c @@ -44,6 +44,8 @@ * SEH or C++ destructor support. */ +#ifdef __CLEANUP_C + ptw32_cleanup_t * ptw32_pop_cleanup (int execute) /* @@ -144,3 +146,5 @@ ptw32_push_cleanup (ptw32_cleanup_t * cleanup, pthread_setspecific (ptw32_cleanupKey, (void *) cleanup); } /* ptw32_push_cleanup */ + +#endif \ No newline at end of file diff --git a/3rdparty/w32pthreads/dll.c b/3rdparty/w32pthreads/dll.c index 50f09d0742..88b495b91d 100644 --- a/3rdparty/w32pthreads/dll.c +++ b/3rdparty/w32pthreads/dll.c @@ -35,6 +35,7 @@ */ #include "ptw32pch.h" +#include #ifndef PTW32_STATIC_LIB @@ -81,6 +82,10 @@ DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_DETACH: (void) pthread_win32_thread_detach_np (); result = pthread_win32_process_detach_np (); + + if( ptw32_testcancel_enable != 0 ) + assert(0); + break; } diff --git a/3rdparty/w32pthreads/include/pthread.h b/3rdparty/w32pthreads/include/pthread.h index 37c0f90bbc..92b52da529 100644 --- a/3rdparty/w32pthreads/include/pthread.h +++ b/3rdparty/w32pthreads/include/pthread.h @@ -970,7 +970,7 @@ extern void PTW32_CDECL pthread_testcancel (void); PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, void (*init_routine) (void)); -#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#if PTW32_LEVEL >= PTW32_LEVEL_MAX && defined(__CLEANUP_C) PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, diff --git a/3rdparty/w32pthreads/pthread_cancel.c b/3rdparty/w32pthreads/pthread_cancel.c index af3ac74463..afcf000453 100644 --- a/3rdparty/w32pthreads/pthread_cancel.c +++ b/3rdparty/w32pthreads/pthread_cancel.c @@ -94,10 +94,6 @@ pthread_cancel (pthread_t thread) cancel_self = pthread_equal (thread, self); tp = (ptw32_thread_t *) thread.p; - // enables full cancel testing in pthread_testcancel, which is normally - // disabled because - _InterlockedIncrement( &ptw32_testcancel_enable ); - /* * Lock for async-cancel safety. */ @@ -127,8 +123,18 @@ pthread_cancel (pthread_t thread) /* * Set for deferred cancellation. */ + if (tp->state < PThreadStateCancelPending) { + // enables full cancel testing in pthread_testcancel, which is normally disabled because + // the full test requires a DLL function invocation and TLS lookup. This provides an + // inlinable first-step shortcut for much speedier testing. :) + + // Increment is performed here such that a thread that is already canceling won't get + // counted multiple times. + + _InterlockedIncrement( &ptw32_testcancel_enable ); + tp->state = PThreadStateCancelPending; if (!SetEvent (tp->cancelEvent)) { diff --git a/3rdparty/w32pthreads/pthread_testcancel.c b/3rdparty/w32pthreads/pthread_testcancel.c index 1270eeb167..89ad26fd23 100644 --- a/3rdparty/w32pthreads/pthread_testcancel.c +++ b/3rdparty/w32pthreads/pthread_testcancel.c @@ -90,8 +90,6 @@ pthread_testcancel (void) return; } - _InterlockedDecrement( &ptw32_testcancel_enable ); - (void) pthread_mutex_lock (&sp->cancelLock); if (sp->cancelState != PTHREAD_CANCEL_DISABLE) diff --git a/3rdparty/w32pthreads/ptw32_threadStart.c b/3rdparty/w32pthreads/ptw32_threadStart.c index 0569fea3f8..5c86c22428 100644 --- a/3rdparty/w32pthreads/ptw32_threadStart.c +++ b/3rdparty/w32pthreads/ptw32_threadStart.c @@ -36,6 +36,27 @@ */ #include "ptw32pch.h" +#include + +// This is a "safe" cleanup handler for the cancel optimization. It ensures +// the testcancel_enable flag gets cleared even when threads commit grotesque +// exceptions. + +static void +_cleanup_testcancel_optimization( void* specific ) +{ + ptw32_thread_t * sp = (ptw32_thread_t*)specific; //(ptw32_thread_t *)pthread_getspecific (ptw32_selfThreadKey); + if( (sp != NULL) && + (sp->cancelType == PTHREAD_CANCEL_DEFERRED) && + (sp->state >= PThreadStateCancelPending) + ) + { + assert( ptw32_testcancel_enable > 0 ); + + if( ptw32_testcancel_enable > 0 ) + (void) _InterlockedDecrement( &ptw32_testcancel_enable ); + } +} #ifdef __CLEANUP_SEH @@ -175,7 +196,9 @@ ptw32_threadStart (void *vthreadParms) /* * Run the caller's routine; */ + pthread_cleanup_push( _cleanup_testcancel_optimization, sp ); status = sp->exitStatus = (*start) (arg); + pthread_cleanup_pop( 1 ); #ifdef _UWIN if (--pthread_count <= 0) @@ -324,6 +347,8 @@ ptw32_threadStart (void *vthreadParms) #endif /* __CLEANUP_C */ #endif /* __CLEANUP_SEH */ + //_cleanup_testcancel_optimization(); + #if defined(PTW32_STATIC_LIB) /* * We need to cleanup the pthread now if we have diff --git a/3rdparty/w32pthreads/ptw32_throw.c b/3rdparty/w32pthreads/ptw32_throw.c index 8349cab8af..f7bb5b602e 100644 --- a/3rdparty/w32pthreads/ptw32_throw.c +++ b/3rdparty/w32pthreads/ptw32_throw.c @@ -142,6 +142,7 @@ ptw32_throw (DWORD exception) } +#ifdef __CLEANUP_C void ptw32_pop_cleanup_all (int execute) { @@ -149,7 +150,7 @@ ptw32_pop_cleanup_all (int execute) { } } - +#endif DWORD ptw32_get_exception_services_code (void)