From 18fcb27ec91f27789270550a2a005cb773bf2fe0 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Tue, 27 Oct 2026 22:53:25 +0100 Subject: The main event loop(s) now also catch an EINTR and return instead of blocking --- opentracker.c | 2 +- ot_event.c | 18 ++++++++++++------ tests/integration/harness.py | 6 ++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/opentracker.c b/opentracker.c index 34b8fd5..a546fc5 100644 --- a/opentracker.c +++ b/opentracker.c @@ -84,7 +84,7 @@ static void install_signal_handlers(void) { sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; + sa.sa_flags = 0; if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1)) panic("install_signal_handlers"); diff --git a/ot_event.c b/ot_event.c index ce0feef..1542bf5 100644 --- a/ot_event.c +++ b/ot_event.c @@ -83,8 +83,10 @@ int event_wait(ot_event *out, int max, int timeout_ms) { g_ready_space = max; } - while ((count = epoll_wait(g_epoll, g_ready, max, timeout_ms)) == -1 && errno == EINTR) - ; + /* An interrupted wait is reported as no events rather than retried here, + so that the caller gets to look at whatever the signal was about */ + if ((count = epoll_wait(g_epoll, g_ready, max, timeout_ms)) == -1) + return errno == EINTR ? 0 : -1; for (i = 0; i < count; ++i) { uint32_t events = g_ready[i].events; @@ -189,8 +191,10 @@ int event_wait(ot_event *out, int max, int timeout_ms) { deadline = &timeout; } - while ((count = kevent(g_kqueue, NULL, 0, g_ready, max, deadline)) == -1 && errno == EINTR) - ; + /* An interrupted wait is reported as no events rather than retried here, + so that the caller gets to look at whatever the signal was about */ + if ((count = kevent(g_kqueue, NULL, 0, g_ready, max, deadline)) == -1) + return errno == EINTR ? 0 : -1; for (i = 0; i < count; ++i) { uint64_t udata = (uint64_t)(uintptr_t)g_ready[i].udata; int eof = (g_ready[i].flags & (EV_EOF | EV_ERROR)) != 0; @@ -310,8 +314,10 @@ int event_del(int fd) { int event_wait(ot_event *out, int max, int timeout_ms) { int ready, found = 0, i; - while ((ready = poll(g_pfds, (nfds_t)g_count, timeout_ms)) == -1 && errno == EINTR) - ; + /* An interrupted wait is reported as no events rather than retried here, + so that the caller gets to look at whatever the signal was about */ + if ((ready = poll(g_pfds, (nfds_t)g_count, timeout_ms)) == -1) + return errno == EINTR ? 0 : -1; if (ready <= 0) return ready; diff --git a/tests/integration/harness.py b/tests/integration/harness.py index 03a0561..122c36d 100644 --- a/tests/integration/harness.py +++ b/tests/integration/harness.py @@ -121,6 +121,7 @@ class Tracker: all: LeakSanitizer reports from an exit handler, so a killed tracker reports nothing and the suite passes over leaks it never looked for. """ + refused_to_exit = False if self.process is not None and self.process.poll() is None: self.process.send_signal(signal.SIGINT) try: @@ -128,11 +129,16 @@ class Tracker: except subprocess.TimeoutExpired: self.process.kill() self.process.wait() + refused_to_exit = True complaints = [ line for line in self.output().splitlines() if "Sanitizer" in line or "runtime error" in line or line.startswith("ERROR") ] + if refused_to_exit: + # Killing it throws away whatever the sanitizer had to say on the + # way out, so a test that ends this way has checked nothing. + complaints.append("the tracker did not exit within 5 s of SIGINT and had to be killed") self._cleanup() return complaints -- cgit v1.3