summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWander Hillen <wjw.hillen@gmail.com>2023-01-20 19:57:48 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2023-01-24 20:02:26 -0500
commite5383a2917a611e20852b9de7c4ccfc066cda9f9 (patch)
tree8a425cba4fb3919ade419de8d4571fb77b747717
parentd151546e59a50158f25c3df6728b00d3c27bb4b9 (diff)
downloadhaskell-e5383a2917a611e20852b9de7c4ccfc066cda9f9.tar.gz
Allow waiting for timerfd to be interrupted during rts shutdown
-rw-r--r--docs/users_guide/9.8.1-notes.rst72
-rw-r--r--rts/posix/ticker/Pthread.c68
2 files changed, 127 insertions, 13 deletions
diff --git a/docs/users_guide/9.8.1-notes.rst b/docs/users_guide/9.8.1-notes.rst
index b35dc92e60..6d94368456 100644
--- a/docs/users_guide/9.8.1-notes.rst
+++ b/docs/users_guide/9.8.1-notes.rst
@@ -10,4 +10,74 @@ Compiler
~~~~~~~~
- Added a new warning :ghc-flag:`-Wterm-variable-capture` that helps to make code compatible with
- the future extension ``RequiredTypeArguments``. \ No newline at end of file
+ the future extension ``RequiredTypeArguments``.
+=======
+
+GHCi
+~~~~
+
+
+Runtime system
+~~~~~~~~~~~~~~
+
+- On POSIX systems that support timerfd, RTS shutdown no longer has to wait for
+ the next RTS 'tick' to occur before continuing the shutdown process. See #22692.
+
+``base`` library
+~~~~~~~~~~~~~~~~
+
+
+``ghc-prim`` library
+~~~~~~~~~~~~~~~~~~~~
+
+``ghc`` library
+~~~~~~~~~~~~~~~
+
+``ghc-heap`` library
+~~~~~~~~~~~~~~~~~~~~
+
+
+Included libraries
+------------------
+
+The package database provided with this distribution also contains a number of
+packages other than GHC itself. See the changelogs provided with these packages
+for further change information.
+
+.. ghc-package-list::
+
+ libraries/array/array.cabal: Dependency of ``ghc`` library
+ libraries/base/base.cabal: Core library
+ libraries/binary/binary.cabal: Dependency of ``ghc`` library
+ libraries/bytestring/bytestring.cabal: Dependency of ``ghc`` library
+ libraries/Cabal/Cabal/Cabal.cabal: Dependency of ``ghc-pkg`` utility
+ libraries/Cabal/Cabal-syntax/Cabal-syntax.cabal: Dependency of ``ghc-pkg`` utility
+ libraries/containers/containers/containers.cabal: Dependency of ``ghc`` library
+ libraries/deepseq/deepseq.cabal: Dependency of ``ghc`` library
+ libraries/directory/directory.cabal: Dependency of ``ghc`` library
+ libraries/exceptions/exceptions.cabal: Dependency of ``ghc`` and ``haskeline`` library
+ libraries/filepath/filepath.cabal: Dependency of ``ghc`` library
+ compiler/ghc.cabal: The compiler itself
+ libraries/ghci/ghci.cabal: The REPL interface
+ libraries/ghc-boot/ghc-boot.cabal: Internal compiler library
+ libraries/ghc-boot-th/ghc-boot-th.cabal: Internal compiler library
+ libraries/ghc-compact/ghc-compact.cabal: Core library
+ libraries/ghc-heap/ghc-heap.cabal: GHC heap-walking library
+ libraries/ghc-prim/ghc-prim.cabal: Core library
+ libraries/haskeline/haskeline.cabal: Dependency of ``ghci`` executable
+ libraries/hpc/hpc.cabal: Dependency of ``hpc`` executable
+ libraries/integer-gmp/integer-gmp.cabal: Core library
+ libraries/libiserv/libiserv.cabal: Internal compiler library
+ libraries/mtl/mtl.cabal: Dependency of ``Cabal`` library
+ libraries/parsec/parsec.cabal: Dependency of ``Cabal`` library
+ libraries/pretty/pretty.cabal: Dependency of ``ghc`` library
+ libraries/process/process.cabal: Dependency of ``ghc`` library
+ libraries/stm/stm.cabal: Dependency of ``haskeline`` library
+ libraries/template-haskell/template-haskell.cabal: Core library
+ libraries/terminfo/terminfo.cabal: Dependency of ``haskeline`` library
+ libraries/text/text.cabal: Dependency of ``Cabal`` library
+ libraries/time/time.cabal: Dependency of ``ghc`` library
+ libraries/transformers/transformers.cabal: Dependency of ``ghc`` library
+ libraries/unix/unix.cabal: Dependency of ``ghc`` library
+ libraries/Win32/Win32.cabal: Dependency of ``ghc`` library
+ libraries/xhtml/xhtml.cabal: Dependency of ``haddock`` executable
diff --git a/rts/posix/ticker/Pthread.c b/rts/posix/ticker/Pthread.c
index a4c7af588f..e2bdf4bae4 100644
--- a/rts/posix/ticker/Pthread.c
+++ b/rts/posix/ticker/Pthread.c
@@ -43,6 +43,7 @@
#include "Proftimer.h"
#include "Schedule.h"
#include "posix/Clock.h"
+#include <sys/poll.h>
#include <time.h>
#if HAVE_SYS_TIME_H
@@ -95,28 +96,53 @@ static OSThreadId thread;
// file descriptor for the timer (Linux only)
static int timerfd = -1;
+// pipe for signaling exit
+static int pipefds[2];
+
static void *itimer_thread_func(void *_handle_tick)
{
TickProc handle_tick = _handle_tick;
uint64_t nticks;
+ ssize_t r = 0;
+ struct pollfd pollfds[2];
+
+#if USE_TIMERFD_FOR_ITIMER
+ pollfds[0].fd = pipefds[0];
+ pollfds[0].events = POLLIN;
+ pollfds[1].fd = timerfd;
+ pollfds[1].events = POLLIN;
+#endif
// Relaxed is sufficient: If we don't see that exited was set in one iteration we will
// see it next time.
TSAN_ANNOTATE_BENIGN_RACE(&exited, "itimer_thread_func");
while (!RELAXED_LOAD(&exited)) {
if (USE_TIMERFD_FOR_ITIMER) {
- ssize_t r = read(timerfd, &nticks, sizeof(nticks));
- if ((r == 0) && (errno == 0)) {
- /* r == 0 is expected only for non-blocking fd (in which case
- * errno should be EAGAIN) but we use a blocking fd.
- *
- * Due to a kernel bug (cf https://lkml.org/lkml/2019/8/16/335)
- * on some platforms we could see r == 0 and errno == 0.
- */
- IF_DEBUG(scheduler, debugBelch("read(timerfd) returned 0 with errno=0. This is a known kernel bug. We just ignore it."));
+ if (poll(pollfds, 2, -1) == -1) {
+ sysErrorBelch("Ticker: poll failed: %s", strerror(errno));
}
- else if (r != sizeof(nticks) && errno != EINTR) {
- barf("Ticker: read(timerfd) failed with %s and returned %zd", strerror(errno), r);
+
+ // We check the pipe first, even though the timerfd may also have triggered.
+ if (pollfds[0].revents & POLLIN) {
+ // the pipe is ready for reading, the only possible reason is that we're exiting
+ exited = true; // set this again to make sure even RELAXED_LOAD will read the proper value
+ // no further action needed, skip ahead to handling the final tick and then stopping
+ }
+ else if (pollfds[1].revents & POLLIN) { // the timerfd is ready for reading
+ r = read(timerfd, &nticks, sizeof(nticks)); // this should never block now
+
+ if ((r == 0) && (errno == 0)) {
+ /* r == 0 is expected only for non-blocking fd (in which case
+ * errno should be EAGAIN) but we use a blocking fd.
+ *
+ * Due to a kernel bug (cf https://lkml.org/lkml/2019/8/16/335)
+ * on some platforms we could see r == 0 and errno == 0.
+ */
+ IF_DEBUG(scheduler, debugBelch("read(timerfd) returned 0 with errno=0. This is a known kernel bug. We just ignore it."));
+ }
+ else if (r != sizeof(nticks) && errno != EINTR) {
+ barf("Ticker: read(timerfd) failed with %s and returned %zd", strerror(errno), r);
+ }
}
} else {
if (rtsSleep(itimer_interval) != 0) {
@@ -138,8 +164,10 @@ static void *itimer_thread_func(void *_handle_tick)
}
}
- if (USE_TIMERFD_FOR_ITIMER)
+ if (USE_TIMERFD_FOR_ITIMER) {
close(timerfd);
+ }
+
return NULL;
}
@@ -185,6 +213,10 @@ initTicker (Time interval, TickProc handle_tick)
if (timerfd_settime(timerfd, 0, &it, NULL)) {
barf("timerfd_settime: %s", strerror(errno));
}
+
+ if (pipe(pipefds) < 0) {
+ barf("pipe: %s", strerror(errno));
+ }
#endif
/*
@@ -237,9 +269,21 @@ exitTicker (bool wait)
// wait for ticker to terminate if necessary
if (wait) {
+#if USE_TIMERFD_FOR_ITIMER
+ // write anything to the pipe to trigger poll() in the ticker thread
+ if (write(pipefds[1], "stop", 5) < 0) {
+ sysErrorBelch("Ticker: Failed to write to pipe: %s", strerror(errno));
+ }
+#endif
if (pthread_join(thread, NULL)) {
sysErrorBelch("Ticker: Failed to join: %s", strerror(errno));
}
+#if USE_TIMERFD_FOR_ITIMER
+ // These need to happen AFTER the ticker thread has finished to prevent a race condition
+ // where the ticker thread closes the read end of the pipe before we're done writing to it.
+ close(pipefds[0]);
+ close(pipefds[1]);
+#endif
closeMutex(&mutex);
closeCondition(&start_cond);
} else {