Skip to content

Commit 2dbf83c

Browse files
authored
Merge pull request #99 from dgrove-oss/dispatch-main-zombie
Linux: avoid zombie process when dispatch_main is called
2 parents ecc14fa + cf9fe36 commit 2dbf83c

File tree

1 file changed

+15
-0
lines changed

1 file changed

+15
-0
lines changed

src/queue.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#define pthread_workqueue_t void*
4949
#endif
5050

51+
static void _dispatch_sig_thread(void *ctxt);
5152
static void _dispatch_cache_cleanup(void *value);
5253
static void _dispatch_sync_f(dispatch_queue_t dq, void *ctxt,
5354
dispatch_function_t func, pthread_priority_t pp);
@@ -5693,6 +5694,17 @@ dispatch_main(void)
56935694
_dispatch_object_debug(&_dispatch_main_q, "%s", __func__);
56945695
_dispatch_program_is_probably_callback_driven = true;
56955696
_dispatch_ktrace0(ARIADNE_ENTER_DISPATCH_MAIN_CODE);
5697+
#ifdef __linux__
5698+
// On Linux, if the main thread calls pthread_exit, the process becomes a zombie.
5699+
// To avoid that, just before calling pthread_exit we register a TSD destructor
5700+
// that will call _dispatch_sig_thread -- thus capturing the main thread in sigsuspend.
5701+
// This relies on an implementation detail (currently true in glibc) that TSD destructors
5702+
// will be called in the order of creation to cause all the TSD cleanup functions to
5703+
// run before the thread becomes trapped in sigsuspend.
5704+
pthread_key_t dispatch_main_key;
5705+
pthread_key_create(&dispatch_main_key, _dispatch_sig_thread);
5706+
pthread_setspecific(dispatch_main_key, &dispatch_main_key);
5707+
#endif
56965708
pthread_exit(NULL);
56975709
DISPATCH_INTERNAL_CRASH(errno, "pthread_exit() returned");
56985710
#if HAVE_PTHREAD_MAIN_NP
@@ -5776,11 +5788,14 @@ _dispatch_queue_cleanup2(void)
57765788
// overload the "probably" variable to mean that dispatch_main() or
57775789
// similar non-POSIX API was called
57785790
// this has to run before the DISPATCH_COCOA_COMPAT below
5791+
// See dispatch_main for call to _dispatch_sig_thread on linux.
5792+
#ifndef __linux__
57795793
if (_dispatch_program_is_probably_callback_driven) {
57805794
_dispatch_barrier_async_detached_f(_dispatch_get_root_queue(
57815795
_DISPATCH_QOS_CLASS_DEFAULT, true), NULL, _dispatch_sig_thread);
57825796
sleep(1); // workaround 6778970
57835797
}
5798+
#endif
57845799

57855800
#if DISPATCH_COCOA_COMPAT
57865801
dispatch_once_f(&_dispatch_main_q_port_pred, dq,

0 commit comments

Comments
 (0)