[PATCH 5/5] batctl: tpmeter: don't cancel test from the signal handler

Sven Eckelmann <[email protected]> Tue, 07 Jul 2026 21:17:04 +0200
Newsgroups org.open-mesh.lists.batman
Message-ID <[email protected]>
tp_sig_handler() calls fflush() and tp_meter_stop() directly from signal
context. tp_meter_stop() allocates a netlink message with nlmsg_alloc() and
sends it via nl_send_auto_complete() - none of these functions (nor fflush)
are async-signal-safe.

Let the signal handler only set a flag. tp_recv_result() now waits for the
result notification with poll(), which is not restarted when a signal
arrives, and sends the CANCEL request from the main flow before continuing
to wait for the (then canceled) test result.

Fixes: f109b3473f86 ("batctl: introduce throughput meter support")
Signed-off-by: Sven Eckelmann <[email protected]>
---
 throughputmeter.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/throughputmeter.c b/throughputmeter.c
index 6799c93..dbb88f6 100644
--- a/throughputmeter.c
+++ b/throughputmeter.c
@@ -17,6 +17,7 @@
 #include <inttypes.h>
 #include <limits.h>
 #include <net/if.h>
+#include <poll.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -34,6 +35,7 @@
 
 static struct ether_addr *dst_mac;
 static struct state *tp_state;
+static volatile sig_atomic_t tp_aborted;
 
 struct tp_result {
 	int error;
@@ -194,8 +196,15 @@ static int no_seq_check(struct nl_msg *msg __maybe_unused,
 	return NL_OK;
 }
 
+static int tp_meter_stop(struct state *state, struct ether_addr *dst_mac);
+
 static int tp_recv_result(struct nl_sock *sock, struct tp_result *result)
 {
+	struct pollfd pfd = {
+		.fd = nl_socket_get_fd(sock),
+		.events = POLLIN,
+	};
+	bool cancel_sent = false;
 	struct nl_cb *cb;
 	int err = 0;
 	int ret;
@@ -207,6 +216,23 @@ static int tp_recv_result(struct nl_sock *sock, struct tp_result *result)
 	nl_cb_err(cb, NL_CB_CUSTOM, tpmeter_nl_print_error, result);
 
 	while (result->error == 0 && !result->found) {
+		if (tp_aborted && !cancel_sent) {
+			cancel_sent = true;
+			tp_meter_stop(tp_state, dst_mac);
+		}
+
+		/* wake up regularly to notice an abort even when the signal
+		 * arrived outside of poll()
+		 */
+		ret = poll(&pfd, 1, 1000);
+		if (ret < 0) {
+			if (errno == EINTR)
+				continue;
+			break;
+		}
+		if (ret == 0)
+			continue;
+
 		ret = nl_recvmsgs(sock, cb);
 		if (ret < 0)
 			break;
@@ -295,8 +321,7 @@ void tp_sig_handler(int sig)
 	switch (sig) {
 	case SIGINT:
 	case SIGTERM:
-		fflush(stdout);
-		tp_meter_stop(tp_state, dst_mac);
+		tp_aborted = 1;
 		break;
 	default:
 		break;

-- 
2.47.3