summaryrefslogtreecommitdiff
path: root/pthread_stop_world.c
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2017-11-17 21:32:40 +0300
committerIvan Maidanski <ivmai@mail.ru>2017-11-17 21:32:40 +0300
commitaf409e4bdfa25bbab911a706a9f123d98be54c23 (patch)
tree0d66052d48debef0ba146600942374bc926e4b7e /pthread_stop_world.c
parent70d0bab7e331ca50d42bab75d85174abab7e1f80 (diff)
downloadbdwgc-af409e4bdfa25bbab911a706a9f123d98be54c23.tar.gz
Workaround hangs in sigsuspend and sem_wait if compiled with TSan
Issue #181 (bdwgc). * pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL && THREAD_SANITIZER] (GC_suspend_handler_inner): Call pthread_sigmask(SIG_SETMASK) with an empty set (thus unmask all signals); add comment. * pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL && THREAD_SANITIZER] (GC_stop_world): Call sem_trywait() repeatedly (with a delay of 100 microseconds) while getting EAGAIN error (instead of a sem_wait call).
Diffstat (limited to 'pthread_stop_world.c')
-rw-r--r--pthread_stop_world.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/pthread_stop_world.c b/pthread_stop_world.c
index cfb4c1ae..0f965726 100644
--- a/pthread_stop_world.c
+++ b/pthread_stop_world.c
@@ -310,6 +310,16 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED,
me -> backing_store_ptr = GC_save_regs_in_stack();
# endif
+# ifdef THREAD_SANITIZER
+ /* TSan disables signals around signal handlers. */
+ {
+ sigset_t set;
+ sigemptyset(&set);
+ if (pthread_sigmask(SIG_SETMASK, &set, NULL) != 0)
+ ABORT("pthread_sigmask(SIG_SETMASK) failed");
+ }
+# endif
+
/* Tell the thread that wants to stop the world that this */
/* thread has been stopped. Note that sem_post() is */
/* the only async-signal-safe primitive in LinuxThreads. */
@@ -827,7 +837,14 @@ GC_INNER void GC_stop_world(void)
for (i = 0; i < n_live_threads; i++) {
retry:
- code = sem_wait(&GC_suspend_ack_sem);
+# ifdef THREAD_SANITIZER
+ /* sem_wait() hangs sometimes. */
+ while ((code = sem_trywait(&GC_suspend_ack_sem)) != 0
+ && errno == EAGAIN)
+ usleep(100);
+# else
+ code = sem_wait(&GC_suspend_ack_sem);
+# endif
if (0 != code) {
/* On Linux, sem_wait is documented to always return zero. */
/* But the documentation appears to be incorrect. */