@@ -961,9 +961,57 @@ _dispatch_install_thread_detach_callback(dispatch_function_t cb)
961
961
}
962
962
#endif
963
963
964
+ #if defined(_WIN32 )
965
+ static bool
966
+ _dispatch_process_is_exiting (void )
967
+ {
968
+ // The goal here is to detect if the current thread is executing cleanup
969
+ // code (e.g. FLS destructors) as a result of calling ExitProcess(). Windows
970
+ // doesn't provide an official method of getting this information, so we
971
+ // take advantage of how ExitProcess() works internally. The first thing
972
+ // that it does (according to MSDN) is terminate every other thread in the
973
+ // process. Logically, it should not be possible to create more threads
974
+ // after this point, and Windows indeed enforces this. Try to create a
975
+ // lightweight suspended thread, and if access is denied, assume that this
976
+ // is because the process is exiting.
977
+ //
978
+ // We aren't worried about any race conditions here during process exit.
979
+ // Cleanup code is only run on the thread that already called ExitProcess(),
980
+ // and every other thread will have been forcibly terminated by the time
981
+ // that happens. Additionally, while CreateThread() could conceivably fail
982
+ // due to resource exhaustion, the process would already be in a bad state
983
+ // if that happens. This is only intended to prevent unwanted cleanup code
984
+ // from running, so the worst case is that a thread doesn't clean up after
985
+ // itself when the process is about to die anyway.
986
+ const size_t stack_size = 1 ; // As small as possible
987
+ HANDLE thread = CreateThread (NULL , stack_size , NULL , NULL ,
988
+ CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION , NULL );
989
+ if (thread ) {
990
+ // Although Microsoft recommends against using TerminateThread, it's
991
+ // safe to use it here because we know that the thread is suspended and
992
+ // it has not executed any code due to a NULL lpStartAddress. There was
993
+ // a bug in Windows Server 2003 and Windows XP where the initial stack
994
+ // would not be freed, but libdispatch does not support them anyway.
995
+ TerminateThread (thread , 0 );
996
+ CloseHandle (thread );
997
+ return false;
998
+ }
999
+ return GetLastError () == ERROR_ACCESS_DENIED ;
1000
+ }
1001
+ #endif
1002
+
964
1003
void DISPATCH_TSD_DTOR_CC
965
1004
_libdispatch_tsd_cleanup (void * ctx )
966
1005
{
1006
+ #if defined(_WIN32 )
1007
+ // On Windows, exiting a process will still call FLS destructors for the
1008
+ // thread that called ExitProcess(). pthreads-based platforms don't call key
1009
+ // destructors on exit, so be consistent.
1010
+ if (_dispatch_process_is_exiting ()) {
1011
+ return ;
1012
+ }
1013
+ #endif
1014
+
967
1015
struct dispatch_tsd * tsd = (struct dispatch_tsd * ) ctx ;
968
1016
969
1017
_tsd_call_cleanup (dispatch_priority_key , NULL );
0 commit comments