summaryrefslogtreecommitdiffstats
path: root/src/poll.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/poll.c')
-rw-r--r--src/poll.c37
1 files changed, 20 insertions, 17 deletions
diff --git a/src/poll.c b/src/poll.c
index f05a345..a74d249 100644
--- a/src/poll.c
+++ b/src/poll.c
@@ -133,23 +133,19 @@ void fastd_poll_handle(void) {
if (timeout < 0 || timeout > maintenance_timeout)
timeout = maintenance_timeout;
- sigset_t set, oldset;
+ sigset_t set;
sigemptyset(&set);
- pthread_sigmask(SIG_SETMASK, &set, &oldset);
struct epoll_event events[16];
- int ret = epoll_wait(ctx.epoll_fd, events, 16, timeout);
- if (ret < 0) {
- if (errno == EINTR)
- return;
-
+ int ret = epoll_pwait(ctx.epoll_fd, events, 16, timeout, &set);
+ if (ret < 0 && errno != EINTR)
exit_errno("epoll_wait");
- }
-
- pthread_sigmask(SIG_SETMASK, &oldset, NULL);
fastd_update_time();
+ if (ret < 0)
+ return;
+
size_t i;
for (i = 0; i < (size_t)ret; i++) {
if (events[i].data.ptr == &ctx.tunfd) {
@@ -257,18 +253,25 @@ void fastd_poll_handle(void) {
sigemptyset(&set);
pthread_sigmask(SIG_SETMASK, &set, &oldset);
- int ret = poll(VECTOR_DATA(ctx.pollfds), VECTOR_LEN(ctx.pollfds), timeout);
- if (ret < 0) {
- if (errno == EINTR)
- return;
-
- exit_errno("poll");
+ int ret = -1;
+
+ if (!fastd_signalled()) {
+ /*
+ There is a race condition here: if a signal occurs after the fastd_signalled() check, but before the poll
+ call, poll() will be called with its normal timeout, potentially delaying the actual signal handling. On
+ OpenBSD we could use ppoll() to fix this, but on FreeBSD we're out of luck.
+ */
+ ret = poll(VECTOR_DATA(ctx.pollfds), VECTOR_LEN(ctx.pollfds), timeout);
+ if (ret < 0 && errno != EINTR)
+ exit_errno("poll");
}
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
-
fastd_update_time();
+ if (ret < 0)
+ return;
+
if (VECTOR_INDEX(ctx.pollfds, 0).revents & POLLIN)
fastd_tuntap_handle();
if (VECTOR_INDEX(ctx.pollfds, 1).revents & POLLIN)