diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2022-04-02 14:36:29 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2022-04-02 14:36:29 +0300 |
commit | ba0616b09bd3354ea9f27ec1ffc1480adbab78b8 (patch) | |
tree | 16651c3ef92598194b44700ff5ae7eef5781a52b /pthread_stop_world.c | |
parent | 934e24bce13897c006876343f6496bc40eddd5b8 (diff) | |
download | bdwgc-ba0616b09bd3354ea9f27ec1ffc1480adbab78b8.tar.gz |
Avoid hang in usleep during signals resend in child process if TSan
Issue #236 (bdwgc).
If a multi-threaded process has been forked, then TSan (as of now)
cannot reasonably function in the child, e.g. usleep() may hang
because some internal lock is not released at fork. The current
solution is just to disable signals resend in the child process
if there are threads not survived during fork.
* include/private/pthread_stop_world.h [CAN_HANDLE_FORK
&& THREAD_SANITIZER && SIGNAL_BASED_STOP_WORLD] (GC_retry_signals):
Declare GC_EXTERN variable.
* pthread_stop_world.c [CAN_HANDLE_FORK && THREAD_SANITIZER]
(GC_retry_signals): Define as GC_INNER (instead of STATIC).
* pthread_stop_world.c (GC_retry_signals): Always initialize to FALSE;
move comment to GC_stop_init.
* pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL
&& !NO_RETRY_SIGNALS] (GC_stop_init): Set GC_retry_signals to TRUE.
* pthread_support.c [CAN_HANDLE_FORK] (GC_remove_all_threads_but_me):
Update comment; change return type to GC_bool; define, set and return
removed local variable.
* pthread_support.c [CAN_HANDLE_FORK] (fork_child_proc): Define
threads_removed local variable and set it to the result of
GC_remove_all_threads_but_me().
* pthread_support.c [CAN_HANDLE_FORK && THREAD_SANITIZER
&& SIGNAL_BASED_STOP_WORLD] (fork_child_proc): If threads_removed or
GC_parallel then GC_retry_signals set to FALSE; add comment.
Diffstat (limited to 'pthread_stop_world.c')
-rw-r--r-- | pthread_stop_world.c | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/pthread_stop_world.c b/pthread_stop_world.c index ba0771c9..cbb3b2b8 100644 --- a/pthread_stop_world.c +++ b/pthread_stop_world.c @@ -142,13 +142,12 @@ STATIC volatile AO_t GC_stop_count; /* before they are expected to stop (unless */ /* they have stopped voluntarily). */ -#ifndef NO_RETRY_SIGNALS - /* Any platform could lose signals, so let's be conservative and */ - /* always enable signals retry logic. */ - STATIC GC_bool GC_retry_signals = TRUE; +#if defined(CAN_HANDLE_FORK) && defined(THREAD_SANITIZER) + GC_INNER #else - STATIC GC_bool GC_retry_signals = FALSE; + STATIC #endif + GC_bool GC_retry_signals = FALSE; /* * We use signals to stop threads during GC. @@ -1404,6 +1403,11 @@ GC_INNER void GC_stop_init(void) if (sigdelset(&suspend_handler_mask, GC_sig_thr_restart) != 0) ABORT("sigdelset failed"); +# ifndef NO_RETRY_SIGNALS + /* Any platform could lose signals, so let's be conservative and */ + /* always enable signals retry logic. */ + GC_retry_signals = TRUE; +# endif /* Override the default value of GC_retry_signals. */ str = GETENV("GC_RETRY_SIGNALS"); if (str != NULL) { @@ -1418,6 +1422,7 @@ GC_INNER void GC_stop_init(void) GC_COND_LOG_PRINTF( "Will retry suspend and restart signals if necessary\n"); } + # ifndef NO_SIGNALS_UNBLOCK_IN_MAIN /* Explicitly unblock the signals once before new threads creation. */ GC_unblock_gc_signals(); |