summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain Henry <sylvain@haskus.fr>2020-04-22 15:50:10 +0200
committerBen Gamari <ben@smart-cactus.org>2020-05-27 23:14:28 -0400
commit9037a2b64ec78cc6d6946aae118622517c8163e2 (patch)
tree5c16adfd507c1121457dffb6f5c781d404bbc7ba
parent286cf192474b067d4017cbd05219dfd6e6ec7589 (diff)
downloadhaskell-9037a2b64ec78cc6d6946aae118622517c8163e2.tar.gz
RTS: workaround a Linux kernel bug in timerfd
Reading a timerfd may return 0: https://lkml.org/lkml/2019/8/16/335. This is currently undocumented behavior and documentation "won't happen anytime soon" (https://lkml.org/lkml/2020/2/13/295). With this patch, we just ignore the result instead of crashing. It may fix #18033 but we can't be sure because we don't have enough information. See also this discussion about the kernel bug: https://github.com/Azure/sonic-swss-common/pull/302/files/1f070e7920c2e5d63316c0105bf4481e73d72dc9 (cherry picked from commit 12789d3ac30dd90f77593e99ef51e54b14fbf556)
-rw-r--r--rts/posix/itimer/Pthread.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/rts/posix/itimer/Pthread.c b/rts/posix/itimer/Pthread.c
index 704a46e121..860dc81cb5 100644
--- a/rts/posix/itimer/Pthread.c
+++ b/rts/posix/itimer/Pthread.c
@@ -121,10 +121,18 @@ static void *itimer_thread_func(void *_handle_tick)
while (!exited) {
if (USE_TIMERFD_FOR_ITIMER) {
- if (read(timerfd, &nticks, sizeof(nticks)) != sizeof(nticks)) {
- if (errno != EINTR) {
- barf("Itimer: read(timerfd) failed: %s", strerror(errno));
- }
+ 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."));
+ }
+ else if (r != sizeof(nticks) && errno != EINTR) {
+ barf("Itimer: read(timerfd) failed with %s and returned %zd", strerror(errno), r);
}
} else {
if (usleep(TimeToUS(itimer_interval)) != 0 && errno != EINTR) {