summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorViktor Dukhovni <ietf-dane@dukhovni.org>2021-04-20 13:56:01 -0400
committerViktor Dukhovni <ietf-dane@dukhovni.org>2021-04-20 23:27:36 -0400
commit5b65d9fbe686d0cd8460a80a7c0d78e6520432e4 (patch)
tree12b40b688c24536e425c408f23cb4a21134fc649
parent5344f8404a0ec0cec250bee1f92527950f492f29 (diff)
downloadhaskell-5b65d9fbe686d0cd8460a80a7c0d78e6520432e4.tar.gz
Block signals in the ticker thread
This avoids surprises in the non-threaded runtime with blocked signals killing the process because they're only blocked in the main thread and not in the ticker thread. Also backport improved compile-time detection of pthread_setname_np() and/or
-rw-r--r--configure.ac70
-rw-r--r--rts/posix/OSThreads.c8
-rw-r--r--rts/posix/itimer/Pthread.c37
3 files changed, 102 insertions, 13 deletions
diff --git a/configure.ac b/configure.ac
index c680bf04b5..44586446dd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1162,20 +1162,72 @@ AC_CHECK_FUNC(pthread_create,
AC_DEFINE_UNQUOTED([NEED_PTHREAD_LIB], [$need_lpthread],
[Define 1 if we need to link code using pthreads with -lpthread])
+dnl Setting thread names
+dnl ~~~~~~~~~~~~~~~~~~~~
+dnl The portability situation here is complicated:
+dnl
+dnl * FreeBSD supports pthread_set_name_np in <pthread_np.h>
+dnl and (if not _POSIX_SOURCE) pthread_setname_np() in <pthread.h>
+dnl because of the conditional visibility, we prefer the former.
+dnl * glibc supports pthread_setname_np
+dnl * Darwin supports pthread_setname_np but does not take a
+dnl pthread_t argument.
+dnl
+AC_CHECK_HEADERS([pthread_np.h])
+
dnl ** pthread_setname_np is a recent addition to glibc, and OS X has
dnl a different single-argument version.
AC_CHECK_LIB(pthread, pthread_setname_np)
-AC_MSG_CHECKING(for pthread_setname_np)
-AC_LINK_IFELSE([AC_LANG_PROGRAM(
-[[
-#define _GNU_SOURCE
-#include <pthread.h>
-]],
-[[pthread_setname_np(pthread_self(), "name");]])],
+
+AC_MSG_CHECKING([for pthread_setname_np (Darwin)])
+AC_LINK_IFELSE([
+ AC_LANG_PROGRAM(
+ [[
+ #include <pthread.h>
+ ]],
+ [[pthread_setname_np("name");]]
+ )],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE([HAVE_PTHREAD_SETNAME_NP_DARWIN], [1],
+ [Define to 1 if you have the Darwin version of pthread_setname_np])
+ ],
+ AC_MSG_RESULT(no)
+)
+
+dnl glibc
+AC_MSG_CHECKING([for pthread_setname_np (glibc)])
+AC_LINK_IFELSE([
+ AC_LANG_PROGRAM(
+ [[
+ #define _GNU_SOURCE
+ #include <pthread.h>
+ ]],
+ [[pthread_setname_np(pthread_self(), "name");]]
+ )],
+ [
AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_PTHREAD_SETNAME_NP], [1],
- [Define to 1 if you have the glibc version of pthread_setname_np]),
- AC_MSG_RESULT(no)
+ [Define to 1 if you have the glibc version of pthread_setname_np])
+ ],
+ AC_MSG_RESULT(no)
+)
+
+dnl FreeBSD
+AC_MSG_CHECKING([for pthread_set_name_np])
+AC_LINK_IFELSE([
+ AC_LANG_PROGRAM(
+ [[
+ #include <pthread_np.h>
+ ]],
+ [[pthread_set_name_np(pthread_self(), "name");]]
+ )],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE([HAVE_PTHREAD_SET_NAME_NP], [1],
+ [Define to 1 if you have pthread_set_name_np])
+ ],
+ AC_MSG_RESULT(no)
)
dnl ** check for eventfd which is needed by the I/O manager
diff --git a/rts/posix/OSThreads.c b/rts/posix/OSThreads.c
index 6c09f86c7f..481b0f8c17 100644
--- a/rts/posix/OSThreads.c
+++ b/rts/posix/OSThreads.c
@@ -30,7 +30,7 @@
#if defined(HAVE_PTHREAD_H)
#include <pthread.h>
-#if defined(freebsd_HOST_OS)
+#if defined(HAVE_PTHREAD_NP_H)
#include <pthread_np.h>
#endif
#endif
@@ -137,8 +137,12 @@ createOSThread (OSThreadId* pId, char *name STG_UNUSED,
int result = pthread_create(pId, NULL, startProc, param);
if (!result) {
pthread_detach(*pId);
-#if defined(HAVE_PTHREAD_SETNAME_NP)
+#if defined(HAVE_PTHREAD_SET_NAME_NP)
+ pthread_set_name_np(*pId, name);
+#elif defined(HAVE_PTHREAD_SETNAME_NP)
pthread_setname_np(*pId, name);
+#elif defined(HAVE_PTHREAD_SETNAME_NP_DARWIN)
+ pthread_setname_np(name);
#endif
}
return result;
diff --git a/rts/posix/itimer/Pthread.c b/rts/posix/itimer/Pthread.c
index 6f86337ff5..73b1eba5de 100644
--- a/rts/posix/itimer/Pthread.c
+++ b/rts/posix/itimer/Pthread.c
@@ -62,6 +62,9 @@
#include <string.h>
#include <pthread.h>
+#if defined(HAVE_PTHREAD_NP_H)
+#include <pthread_np.h>
+#endif
#include <unistd.h>
#include <fcntl.h>
@@ -167,6 +170,11 @@ initTicker (Time interval, TickProc handle_tick)
itimer_interval = interval;
stopped = false;
exited = false;
+#if defined(HAVE_SIGNAL_H)
+ sigset_t mask, omask;
+ int sigret;
+#endif
+ int ret;
initCondition(&start_cond);
initMutex(&mutex);
@@ -174,10 +182,35 @@ initTicker (Time interval, TickProc handle_tick)
/*
* We can't use the RTS's createOSThread here as we need to remain attached
* to the thread we create so we can later join to it if requested
+ *
+ * On FreeBSD 12.2 pthread_set_name_np() is unconditionally declared in
+ * <pthread_np.h>, while pthread_setname_np() is conditionally declared in
+ * <pthread.h> when _POSIX_SOURCE is not defined, but we're including
+ * <PosixSource.h>, so must use pthread_set_name_np() instead. See similar
+ * code in "rts/posix/OSThreads.c".
+ *
+ * Create the thread with all blockable signals blocked, leaving signal
+ * handling to the main and/or other threads. This is especially useful in
+ * the non-threaded runtime, where applications might expect sigprocmask(2)
+ * to effectively block signals.
*/
- if (! pthread_create(&thread, NULL, itimer_thread_func, (void*)handle_tick)) {
-#if defined(HAVE_PTHREAD_SETNAME_NP)
+#if defined(HAVE_SIGNAL_H)
+ sigfillset(&mask);
+ sigret = pthread_sigmask(SIG_SETMASK, &mask, &omask);
+#endif
+ ret = pthread_create(&thread, NULL, itimer_thread_func, (void*)handle_tick);
+#if defined(HAVE_SIGNAL_H)
+ if (sigret == 0)
+ pthread_sigmask(SIG_SETMASK, &omask, NULL);
+#endif
+
+ if (ret == 0) {
+#if defined(HAVE_PTHREAD_SET_NAME_NP)
+ pthread_set_name_np(thread, "ghc_ticker");
+#elif defined(HAVE_PTHREAD_SETNAME_NP)
pthread_setname_np(thread, "ghc_ticker");
+#elif defined(HAVE_PTHREAD_SETNAME_NP_DARWIN)
+ pthread_setname_np("ghc_ticker");
#endif
} else {
barf("Itimer: Failed to spawn thread: %s", strerror(errno));