summaryrefslogtreecommitdiff
path: root/pthread_stop_world.c
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2022-04-02 14:36:29 +0300
committerIvan Maidanski <ivmai@mail.ru>2022-04-02 14:36:29 +0300
commitba0616b09bd3354ea9f27ec1ffc1480adbab78b8 (patch)
tree16651c3ef92598194b44700ff5ae7eef5781a52b /pthread_stop_world.c
parent934e24bce13897c006876343f6496bc40eddd5b8 (diff)
downloadbdwgc-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.c15
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();