summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2026-10-27 22:53:25 +0100
committerDirk Engling <erdgeist@erdgeist.org>2026-10-27 22:53:25 +0100
commit18fcb27ec91f27789270550a2a005cb773bf2fe0 (patch)
tree745089165e7dfd3e22a0dc5be88ab77172419b28
parent36c21130fa4fd286e7515d5f6d429df983d253d5 (diff)
The main event loop(s) now also catch an EINTR and return instead of blockingHEADmaster
-rw-r--r--opentracker.c2
-rw-r--r--ot_event.c18
-rw-r--r--tests/integration/harness.py6
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) {
84 84
85 sa.sa_handler = signal_handler; 85 sa.sa_handler = signal_handler;
86 sigemptyset(&sa.sa_mask); 86 sigemptyset(&sa.sa_mask);
87 sa.sa_flags = SA_RESTART; 87 sa.sa_flags = 0;
88 if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1)) 88 if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1))
89 panic("install_signal_handlers"); 89 panic("install_signal_handlers");
90 90
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) {
83 g_ready_space = max; 83 g_ready_space = max;
84 } 84 }
85 85
86 while ((count = epoll_wait(g_epoll, g_ready, max, timeout_ms)) == -1 && errno == EINTR) 86 /* An interrupted wait is reported as no events rather than retried here,
87 ; 87 so that the caller gets to look at whatever the signal was about */
88 if ((count = epoll_wait(g_epoll, g_ready, max, timeout_ms)) == -1)
89 return errno == EINTR ? 0 : -1;
88 for (i = 0; i < count; ++i) { 90 for (i = 0; i < count; ++i) {
89 uint32_t events = g_ready[i].events; 91 uint32_t events = g_ready[i].events;
90 92
@@ -189,8 +191,10 @@ int event_wait(ot_event *out, int max, int timeout_ms) {
189 deadline = &timeout; 191 deadline = &timeout;
190 } 192 }
191 193
192 while ((count = kevent(g_kqueue, NULL, 0, g_ready, max, deadline)) == -1 && errno == EINTR) 194 /* An interrupted wait is reported as no events rather than retried here,
193 ; 195 so that the caller gets to look at whatever the signal was about */
196 if ((count = kevent(g_kqueue, NULL, 0, g_ready, max, deadline)) == -1)
197 return errno == EINTR ? 0 : -1;
194 for (i = 0; i < count; ++i) { 198 for (i = 0; i < count; ++i) {
195 uint64_t udata = (uint64_t)(uintptr_t)g_ready[i].udata; 199 uint64_t udata = (uint64_t)(uintptr_t)g_ready[i].udata;
196 int eof = (g_ready[i].flags & (EV_EOF | EV_ERROR)) != 0; 200 int eof = (g_ready[i].flags & (EV_EOF | EV_ERROR)) != 0;
@@ -310,8 +314,10 @@ int event_del(int fd) {
310int event_wait(ot_event *out, int max, int timeout_ms) { 314int event_wait(ot_event *out, int max, int timeout_ms) {
311 int ready, found = 0, i; 315 int ready, found = 0, i;
312 316
313 while ((ready = poll(g_pfds, (nfds_t)g_count, timeout_ms)) == -1 && errno == EINTR) 317 /* An interrupted wait is reported as no events rather than retried here,
314 ; 318 so that the caller gets to look at whatever the signal was about */
319 if ((ready = poll(g_pfds, (nfds_t)g_count, timeout_ms)) == -1)
320 return errno == EINTR ? 0 : -1;
315 if (ready <= 0) 321 if (ready <= 0)
316 return ready; 322 return ready;
317 323
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:
121 all: LeakSanitizer reports from an exit handler, so a killed tracker 121 all: LeakSanitizer reports from an exit handler, so a killed tracker
122 reports nothing and the suite passes over leaks it never looked for. 122 reports nothing and the suite passes over leaks it never looked for.
123 """ 123 """
124 refused_to_exit = False
124 if self.process is not None and self.process.poll() is None: 125 if self.process is not None and self.process.poll() is None:
125 self.process.send_signal(signal.SIGINT) 126 self.process.send_signal(signal.SIGINT)
126 try: 127 try:
@@ -128,11 +129,16 @@ class Tracker:
128 except subprocess.TimeoutExpired: 129 except subprocess.TimeoutExpired:
129 self.process.kill() 130 self.process.kill()
130 self.process.wait() 131 self.process.wait()
132 refused_to_exit = True
131 complaints = [ 133 complaints = [
132 line 134 line
133 for line in self.output().splitlines() 135 for line in self.output().splitlines()
134 if "Sanitizer" in line or "runtime error" in line or line.startswith("ERROR") 136 if "Sanitizer" in line or "runtime error" in line or line.startswith("ERROR")
135 ] 137 ]
138 if refused_to_exit:
139 # Killing it throws away whatever the sanitizer had to say on the
140 # way out, so a test that ends this way has checked nothing.
141 complaints.append("the tracker did not exit within 5 s of SIGINT and had to be killed")
136 self._cleanup() 142 self._cleanup()
137 return complaints 143 return complaints
138 144