Commit e5383a29 authored by Wander Hillen's avatar Wander Hillen Committed by Marge Bot
Browse files

Allow waiting for timerfd to be interrupted during rts shutdown

parent d151546e
Pipeline #62067 canceled with stages
......@@ -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
......@@ -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 {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment