diff options
author | Wander Hillen <wjw.hillen@gmail.com> | 2023-01-20 19:57:48 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2023-01-24 20:02:26 -0500 |
commit | e5383a2917a611e20852b9de7c4ccfc066cda9f9 (patch) | |
tree | 8a425cba4fb3919ade419de8d4571fb77b747717 | |
parent | d151546e59a50158f25c3df6728b00d3c27bb4b9 (diff) | |
download | haskell-e5383a2917a611e20852b9de7c4ccfc066cda9f9.tar.gz |
Allow waiting for timerfd to be interrupted during rts shutdown
-rw-r--r-- | docs/users_guide/9.8.1-notes.rst | 72 | ||||
-rw-r--r-- | rts/posix/ticker/Pthread.c | 68 |
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 { |