timerfd: use non-blocking mode, fixes dead lock

Since we cancel the timers every now and then, there's a (small)
chance that one handler cancels a timer that has triggered in the same
epoll() iteration.

When this happens, read() blocks.

Fix by making the timer FDs non-blocking, and simply returning when we
read 0 bytes.
This commit is contained in:
Daniel Eklöf 2019-11-02 01:14:40 +01:00
parent 035ace33b6
commit b27cd9cedf
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 25 additions and 5 deletions

View file

@ -117,6 +117,11 @@ fdm_flash(struct fdm *fdm, int fd, int events, void *data)
return false;
}
if (ret == 0) {
/* Cancelled by other handler in *this* epoll() iteration */
return true;
}
LOG_DBG("flash timer expired %llu times",
(unsigned long long)expiration_count);
@ -142,6 +147,11 @@ fdm_blink(struct fdm *fdm, int fd, int events, void *data)
return false;
}
if (ret == 0) {
/* Cancelled by other handler in *this* epoll() iteration */
return true;
}
LOG_DBG("blink timer expired %llu times",
(unsigned long long)expiration_count);
@ -189,6 +199,11 @@ fdm_delayed_render(struct fdm *fdm, int fd, int events, void *data)
return false;
}
if (ret1 == 0 && ret2 == 0) {
/* Cancelled by other handler in *this* epoll() iteration */
return true;
}
render_refresh(term);
/* Reset timers */
@ -304,16 +319,16 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl,
LOG_ERRNO("failed to open PTY");
goto close_fds;
}
if ((flash_fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC)) == -1) {
if ((flash_fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK)) == -1) {
LOG_ERRNO("failed to create flash timer FD");
goto close_fds;
}
if ((blink_fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC)) == -1) {
if ((blink_fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK)) == -1) {
LOG_ERRNO("failed to create blink timer FD");
goto close_fds;
}
if ((delay_lower_fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC)) == -1 ||
(delay_upper_fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC)) == -1)
if ((delay_lower_fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK)) == -1 ||
(delay_upper_fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK)) == -1)
{
LOG_ERRNO("failed to create delayed rendering timer FDs");
goto close_fds;

View file

@ -411,6 +411,11 @@ fdm_repeat(struct fdm *fdm, int fd, int events, void *data)
return false;
}
if (ret == 0) {
/* Cancelled by other handler in *this* epoll() iteration */
return true;
}
wayl->kbd.repeat.dont_re_repeat = true;
for (size_t i = 0; i < expiration_count; i++)
input_repeat(wayl, wayl->kbd.repeat.key);
@ -513,7 +518,7 @@ wayl_init(struct fdm *fdm)
/* All wayland initialization done - make it so */
wl_display_roundtrip(wayl->display);
wayl->kbd.repeat.fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC);
wayl->kbd.repeat.fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK);
if (wayl->kbd.repeat.fd == -1) {
LOG_ERRNO("failed to create keyboard repeat timer FD");
goto out;