From 95947bdc584abab6def8c00d9edf6488c4dfcb1c Mon Sep 17 00:00:00 2001 From: Hiroshi Yokota Date: Sat, 6 Feb 2016 10:25:48 +0900 Subject: [PATCH] Fix user-defined signals drop by marker threads When one user thread sets its own signal handler in multi-threaded code, GC marker thread sometimes steal and drop user signal calls. Because GC marker thread doesn't knows the user thread's signal handler, and uses the default signal handler that ignores any signal call. This becomes to drop the signal call. This patch inhibits to accept signals by GC marker threads except GC system signals, and don't drop user signal calls. This patch comes from Gauche. * include/private/gcconfig.h (NO_MARKER_SPECIAL_SIGMASK): New macro. * pthread_support.c (GC_start_mark_threads_inner): Unless NO_MARKER_SPECIAL_SIGMASK, call pthread_sigmask to block all signals (except for the ones used for GC suspend/resume if any) before starting marker threads and restore signals mask afterwards. * win32_threads.c (GC_start_mark_threads_inner): Likewise. --- include/private/gcconfig.h | 7 +++++++ pthread_support.c | 36 ++++++++++++++++++++++++++++++++++++ win32_threads.c | 26 ++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h index 92d47277..cbc4aaaf 100644 --- a/include/private/gcconfig.h +++ b/include/private/gcconfig.h @@ -2703,6 +2703,13 @@ # define GC_EXPLICIT_SIGNALS_UNBLOCK #endif +#if !defined(NO_MARKER_SPECIAL_SIGMASK) \ + && (defined(NACL) || defined(GC_WIN32_PTHREADS)) + /* Either there is no pthread_sigmask(), or GC marker thread cannot */ + /* steal and drop user signal calls. */ +# define NO_MARKER_SPECIAL_SIGMASK +#endif + #ifdef GC_NETBSD_THREADS # define SIGRTMIN 33 # define SIGRTMAX 63 diff --git a/pthread_support.c b/pthread_support.c index 559c27fc..8f379d2d 100644 --- a/pthread_support.c +++ b/pthread_support.c @@ -394,6 +394,9 @@ STATIC pthread_t GC_mark_threads[MAX_MARKERS]; { int i; pthread_attr_t attr; +# ifndef NO_MARKER_SPECIAL_SIGMASK + sigset_t set, oldset; +# endif GC_ASSERT(I_DONT_HOLD_LOCK()); if (available_markers_m1 <= 0) return; @@ -424,6 +427,30 @@ STATIC pthread_t GC_mark_threads[MAX_MARKERS]; } } # endif /* HPUX || GC_DGUX386_THREADS */ + +# ifndef NO_MARKER_SPECIAL_SIGMASK + /* Apply special signal mask to GC marker threads, and don't drop */ + /* user defined signals by GC marker threads. */ + if (sigfillset(&set) != 0) + ABORT("sigfillset failed"); + +# if !defined(GC_DARWIN_THREADS) && !defined(GC_OPENBSD_UTHREADS) \ + && !defined(NACL) + /* These are used by GC to stop and restart the world. */ + if (sigdelset(&set, GC_get_suspend_signal()) != 0 + || sigdelset(&set, GC_get_thr_restart_signal()) != 0) + ABORT("sigdelset failed"); +# endif + + if (pthread_sigmask(SIG_BLOCK, &set, &oldset) < 0) { + WARN("pthread_sigmask set failed, no markers started," + " errno = %" WARN_PRIdPTR "\n", errno); + GC_markers_m1 = 0; + (void)pthread_attr_destroy(&attr); + return; + } +# endif /* !NO_MARKER_SPECIAL_SIGMASK */ + for (i = 0; i < available_markers_m1; ++i) { if (0 != REAL_FUNC(pthread_create)(GC_mark_threads + i, &attr, GC_mark_thread, (void *)(word)i)) { @@ -434,6 +461,15 @@ STATIC pthread_t GC_mark_threads[MAX_MARKERS]; } } GC_markers_m1 = i; + +# ifndef NO_MARKER_SPECIAL_SIGMASK + /* Restore previous signal mask. */ + if (pthread_sigmask(SIG_SETMASK, &oldset, NULL) < 0) { + WARN("pthread_sigmask restore failed, errno = %" WARN_PRIdPTR "\n", + errno); + } +# endif + (void)pthread_attr_destroy(&attr); GC_wait_for_markers_init(); GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1); diff --git a/win32_threads.c b/win32_threads.c index 53d0acfd..614d5e87 100644 --- a/win32_threads.c +++ b/win32_threads.c @@ -1773,6 +1773,9 @@ GC_INNER void GC_get_next_stack(char *start, char *limit, int i; pthread_attr_t attr; pthread_t new_thread; +# ifndef NO_MARKER_SPECIAL_SIGMASK + sigset_t set, oldset; +# endif GC_ASSERT(I_DONT_HOLD_LOCK()); if (available_markers_m1 <= 0) return; @@ -1786,6 +1789,20 @@ GC_INNER void GC_get_next_stack(char *start, char *limit, if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) ABORT("pthread_attr_setdetachstate failed"); +# ifndef NO_MARKER_SPECIAL_SIGMASK + /* Apply special signal mask to GC marker threads, and don't drop */ + /* user defined signals by GC marker threads. */ + if (sigfillset(&set) != 0) + ABORT("sigfillset failed"); + if (pthread_sigmask(SIG_BLOCK, &set, &oldset) < 0) { + WARN("pthread_sigmask set failed, no markers started," + " errno = %" WARN_PRIdPTR "\n", errno); + GC_markers_m1 = 0; + (void)pthread_attr_destroy(&attr); + return; + } +# endif /* !NO_MARKER_SPECIAL_SIGMASK */ + for (i = 0; i < available_markers_m1; ++i) { marker_last_stack_min[i] = ADDR_LIMIT; if (0 != pthread_create(&new_thread, &attr, @@ -1795,6 +1812,15 @@ GC_INNER void GC_get_next_stack(char *start, char *limit, break; } } + +# ifndef NO_MARKER_SPECIAL_SIGMASK + /* Restore previous signal mask. */ + if (pthread_sigmask(SIG_SETMASK, &oldset, NULL) < 0) { + WARN("pthread_sigmask restore failed, errno = %" WARN_PRIdPTR "\n", + errno); + } +# endif + GC_markers_m1 = i; (void)pthread_attr_destroy(&attr); GC_wait_for_markers_init(); -- 2.40.0