* [PATCH 00/13] make signal handlers async-signal-safe
@ 2026-09-06 23:24 Stephen Hemminger
2026-09-06 23:24 ` [PATCH 01/13] graph: do not call printf in signal Stephen Hemminger
` (14 more replies)
0 siblings, 15 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
Signal handlers may only call the functions listed in signal-safety(7).
Many DPDK examples ignored this and did printf() a "preparing to exit"
message before setting the quit flag. A signal during another printf
call can deadlock. And some of the programs did even more
unsafe things.
GCC 14 -fanalyzer reports these:
warning: call to 'printf' from within signal handler [CWE-479]
[-Wanalyzer-unsafe-call-within-signal-handler]
The fix is the same throughout: the handler only sets the existing
volatile flag, and any real work moves to the main loop or to main()
after the lcores are joined. The message is dropped; the user pressed ^C
and knows a signal was sent.
Patches 1-2 only delete the printf(). Patches 3-13 also relocate work
that was being done in the handler.
Behaviour changes worth review:
- examples/ntb: SIGINT used to printf(), restore SIG_DFL and re-raise,
killing the process without stopping the forwarding lcores or closing
the devices. It now sets the per-lcore stopped flag, so SIGINT stops
forwarding and returns to the ntb> prompt; quit does the teardown.
- examples/vdpa: the teardown moved to main() now also closes the vDPA
devices when leaving interactive mode, which was missing before.
- examples/eventdev_pipeline: the second-signal escape hatch becomes
_exit() instead of rte_exit(), the --dump-dev exit dump moves to
main() (and uses the real dev_id rather than a hardcoded 0), and
SIGTSTP now sets cdata.dump_dev_signal, which schedule_devices()
already drained but nothing ever set. The SIGTSTP dump therefore
requires a scheduler lcore.
Only examples/ethtool and examples/vmdq_dcb carry a Fixes: tag; the rest
remove an unsafe call that has not been seen to deadlock in practice and
are cleanups rather than backport material.
Applications outside the analyzer's reach likely have the same pattern;
this covers what GCC flagged, plus eventdev_pipeline found by inspection.
Build tested with GCC 14 -fanalyzer; the warnings are gone for the files
touched.
Stephen Hemminger (13):
graph: do not call printf in signal
examples: remove printf from signal handler
examples/vmdq: do not print from signal handler
examples/symmetric_mp: do not print or exit in handler
examples/vdpa: make signal handler safe
examples/vhost: make signal handler safe
examples/vhost_blk: do not tear down from signal handler
examples/ntb: do not print and re-raise from signal handler
examples/ipsecgw: do not print from signal handler
examples/l2fwd-macsec: remove print in signal handler
examples/ethtool: fix exit flag and unchecked cmdline
examples/vmdq_dcb: allow exit on signal
examples/eventdev_pipeline: make signal handler safe
app/graph/main.c | 4 +--
examples/distributor/main.c | 3 +--
examples/dma/dmafwd.c | 2 --
examples/ethtool/ethtool-app/ethapp.c | 5 ++++
examples/ethtool/ethtool-app/main.c | 2 +-
examples/eventdev_pipeline/main.c | 18 ++++++--------
examples/eventdev_pipeline/pipeline_common.h | 3 ++-
examples/flow_filtering/main.c | 5 +---
examples/ipsec-secgw/ipsec-secgw.c | 5 +---
examples/l2fwd-event/main.c | 5 +---
examples/l2fwd-macsec/main.c | 5 +---
examples/l2fwd/main.c | 5 +---
examples/l3fwd-graph/main.c | 5 +---
examples/multi_process/symmetric_mp/main.c | 26 ++++++++++++++------
examples/ntb/ntb_fwd.c | 16 +++++++-----
examples/vdpa/main.c | 16 ++++++------
examples/vhost/main.c | 14 ++++++-----
examples/vhost_blk/vhost_blk.c | 26 +++++++++++---------
examples/vmdq/main.c | 20 ++++++++++++---
examples/vmdq_dcb/main.c | 20 ++++++++++++++-
20 files changed, 118 insertions(+), 87 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 01/13] graph: do not call printf in signal
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-06 23:24 ` [PATCH 02/13] examples: remove printf from signal handler Stephen Hemminger
` (13 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Sunil Kumar Kori, Rakesh Kudurumalla
Printf is not signal safe and calling it in a signal handler
get flagged as an error by GCC analyzer.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
app/graph/main.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/app/graph/main.c b/app/graph/main.c
index 56294f2693..d36d60bf94 100644
--- a/app/graph/main.c
+++ b/app/graph/main.c
@@ -49,10 +49,8 @@ static struct app_params {
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n", signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
static int
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 02/13] examples: remove printf from signal handler
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
2026-09-06 23:24 ` [PATCH 01/13] graph: do not call printf in signal Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-06 23:24 ` [PATCH 03/13] examples/vmdq: do not print " Stephen Hemminger
` (12 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev
Cc: Stephen Hemminger, Chengwen Feng, Kevin Laatz, Bruce Richardson,
Ori Kam, Sunil Kumar Kori, Pavan Nikhilesh, Jerin Jacob,
Kiran Kumar K, Nithin Dabilpuram, Zhirun Yan
Printf is not a signal safe function, remove useless printf's
that cause warnings in GCC analyzer.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/distributor/main.c | 3 +--
examples/dma/dmafwd.c | 2 --
examples/eventdev_pipeline/main.c | 2 --
examples/flow_filtering/main.c | 5 +----
examples/l2fwd-event/main.c | 5 +----
examples/l2fwd/main.c | 5 +----
examples/l3fwd-graph/main.c | 5 +----
7 files changed, 5 insertions(+), 22 deletions(-)
diff --git a/examples/distributor/main.c b/examples/distributor/main.c
index ea44939fba..0905482cf0 100644
--- a/examples/distributor/main.c
+++ b/examples/distributor/main.c
@@ -529,9 +529,8 @@ lcore_tx(struct rte_ring *in_r)
}
static void
-int_handler(int sig_num)
+int_handler(int sig_num __rte_unused)
{
- printf("Exiting on signal %d\n", sig_num);
/* set quit flag for rx thread to exit */
quit_signal_rx = 1;
}
diff --git a/examples/dma/dmafwd.c b/examples/dma/dmafwd.c
index a8ed09e6ae..8d195faddb 100644
--- a/examples/dma/dmafwd.c
+++ b/examples/dma/dmafwd.c
@@ -998,8 +998,6 @@ static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
force_quit = true;
} else if (signum == SIGUSR1) {
dmadev_dump();
diff --git a/examples/eventdev_pipeline/main.c b/examples/eventdev_pipeline/main.c
index 0c995d1a70..65e0cd437c 100644
--- a/examples/eventdev_pipeline/main.c
+++ b/examples/eventdev_pipeline/main.c
@@ -319,8 +319,6 @@ signal_handler(int signum)
if (fdata->done)
rte_exit(1, "Exiting on signal %d\n", signum);
if ((signum == SIGINT || signum == SIGTERM) && !once) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
if (cdata.dump_dev)
rte_event_dev_dump(0, stdout);
once = 1;
diff --git a/examples/flow_filtering/main.c b/examples/flow_filtering/main.c
index f2124881a0..b4ccaacea1 100644
--- a/examples/flow_filtering/main.c
+++ b/examples/flow_filtering/main.c
@@ -266,11 +266,8 @@ init_port(void)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
/* Parse the argument given in the command line of the application */
diff --git a/examples/l2fwd-event/main.c b/examples/l2fwd-event/main.c
index 2d31d4c6ad..c492c6dee0 100644
--- a/examples/l2fwd-event/main.c
+++ b/examples/l2fwd-event/main.c
@@ -582,11 +582,8 @@ static void
signal_handler(int signum)
{
struct l2fwd_resources *rsrc = l2fwd_get_rsrc();
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
rsrc->force_quit = true;
- }
}
int
diff --git a/examples/l2fwd/main.c b/examples/l2fwd/main.c
index 1c4a89ae90..851816423f 100644
--- a/examples/l2fwd/main.c
+++ b/examples/l2fwd/main.c
@@ -638,11 +638,8 @@ check_all_ports_link_status(uint32_t port_mask)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
int
diff --git a/examples/l3fwd-graph/main.c b/examples/l3fwd-graph/main.c
index 5f89286dce..4fa302f5b0 100644
--- a/examples/l3fwd-graph/main.c
+++ b/examples/l3fwd-graph/main.c
@@ -753,11 +753,8 @@ check_all_ports_link_status(uint32_t port_mask)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
static void
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 03/13] examples/vmdq: do not print from signal handler
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
2026-09-06 23:24 ` [PATCH 01/13] graph: do not call printf in signal Stephen Hemminger
2026-09-06 23:24 ` [PATCH 02/13] examples: remove printf from signal handler Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-06 23:24 ` [PATCH 04/13] examples/symmetric_mp: do not print or exit in handler Stephen Hemminger
` (11 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
The SIGHUP handler calls printf() which is not async-signal-safe.
Set a flag instead and print the stats from the main lcore in the
forwarding loop.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/vmdq/main.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/examples/vmdq/main.c b/examples/vmdq/main.c
index 8c9d885090..63ac44deba 100644
--- a/examples/vmdq/main.c
+++ b/examples/vmdq/main.c
@@ -465,18 +465,27 @@ update_mac_address(struct rte_mbuf *m, unsigned dst_port)
rte_ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->src_addr);
}
-/* When we receive a HUP signal, print out our stats */
+/* Set by the SIGHUP handler, consumed by the main lcore. */
+static volatile sig_atomic_t stats_requested;
+
+static void
+sighup_handler(__rte_unused int signum)
+{
+ stats_requested = 1;
+}
+
static void
-sighup_handler(int signum)
+print_stats(void)
{
unsigned int q = vmdq_queue_base;
+
for (; q < num_queues; q++) {
if ((q - vmdq_queue_base) % (num_vmdq_queues / num_pools) == 0)
printf("\nPool %u: ", (q - vmdq_queue_base) /
(num_vmdq_queues / num_pools));
printf("%lu ", rxPackets[q]);
}
- printf("\nFinished handling signal %d\n", signum);
+ putchar('\n');
}
/*
@@ -534,6 +543,11 @@ lcore_main(__rte_unused void *dummy)
struct rte_mbuf *buf[MAX_PKT_BURST];
const uint16_t buf_size = RTE_DIM(buf);
+ if (stats_requested && lcore_id == rte_get_main_lcore()) {
+ stats_requested = 0;
+ print_stats();
+ }
+
for (p = 0; p < num_ports; p++) {
const uint8_t sport = ports[p];
/* 0 <-> 1, 2 <-> 3 etc */
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 04/13] examples/symmetric_mp: do not print or exit in handler
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (2 preceding siblings ...)
2026-09-06 23:24 ` [PATCH 03/13] examples/vmdq: do not print " Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-06 23:24 ` [PATCH 05/13] examples/vdpa: make signal handler safe Stephen Hemminger
` (10 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Anatoly Burakov
The SIGINT and SIGTERM handler called printf() and exit() which are
not async-signal-safe.
Set a flag, let the forwarding loops return, and print the stats from
main() after joining the lcores.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/multi_process/symmetric_mp/main.c | 26 ++++++++++++++++------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/examples/multi_process/symmetric_mp/main.c b/examples/multi_process/symmetric_mp/main.c
index 7314a9c6ea..e2d185ab1b 100644
--- a/examples/multi_process/symmetric_mp/main.c
+++ b/examples/multi_process/symmetric_mp/main.c
@@ -92,18 +92,25 @@ smp_usage(const char *prgname, const char *errmsg)
}
-/* signal handler configured for SIGTERM and SIGINT to print stats on exit */
+/* Set by SIGTERM and SIGINT handler to stop the forwarding loops. */
+static volatile sig_atomic_t quit;
+
+static void
+signal_handler(__rte_unused int signum)
+{
+ quit = 1;
+}
+
static void
-print_stats(int signum)
+print_stats(void)
{
unsigned i;
- printf("\nExiting on signal %d\n\n", signum);
+
for (i = 0; i < num_ports; i++){
const uint8_t p_num = ports[i];
printf("Port %u: RX - %u, TX - %u, Drop - %u\n", (unsigned)p_num,
pstats[p_num].rx, pstats[p_num].tx, pstats[p_num].drop);
}
- exit(0);
}
/* Parse the argument given in the command line of the application */
@@ -344,7 +351,7 @@ lcore_main(void *arg __rte_unused)
* queue number corresponding to our process number (not lcore id)
*/
- for (;;) {
+ while (!quit) {
struct rte_mbuf *buf[PKT_BURST];
for (p = start_port; p < end_port; p++) {
@@ -364,6 +371,8 @@ lcore_main(void *arg __rte_unused)
}
}
}
+
+ return 0;
}
/* Check the link status of all ports in up to 9s, and print them finally */
@@ -440,8 +449,8 @@ main(int argc, char **argv)
struct rte_mempool *mp;
/* set up signal handlers to print stats on exit */
- signal(SIGINT, print_stats);
- signal(SIGTERM, print_stats);
+ signal(SIGINT, signal_handler);
+ signal(SIGTERM, signal_handler);
/* initialise the EAL for all */
ret = rte_eal_init(argc, argv);
@@ -484,6 +493,9 @@ main(int argc, char **argv)
RTE_LOG(INFO, APP, "Finished Process Init.\n");
rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MAIN);
+ rte_eal_mp_wait_lcore();
+
+ print_stats();
/* clean up the EAL */
rte_eal_cleanup();
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 05/13] examples/vdpa: make signal handler safe
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (3 preceding siblings ...)
2026-09-06 23:24 ` [PATCH 04/13] examples/symmetric_mp: do not print or exit in handler Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-06 23:24 ` [PATCH 06/13] examples/vhost: " Stephen Hemminger
` (9 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Maxime Coquelin, Chenbo Xia
The handler called printf(), the vhost library teardown path and
exit(), none of which are async-signal-safe.
Set a flag and do the teardown in main() once the input loop returns.
This also closes the vDPA devices on exit from interactive mode, which
was missing before.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/vdpa/main.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/examples/vdpa/main.c b/examples/vdpa/main.c
index ac6da79b05..1b989fc6e5 100644
--- a/examples/vdpa/main.c
+++ b/examples/vdpa/main.c
@@ -288,14 +288,13 @@ vdpa_sample_quit(void)
}
}
+/* Set by SIGINT and SIGTERM handler, consumed by main(). */
+static volatile sig_atomic_t quit;
+
static void
-signal_handler(int signum)
+signal_handler(__rte_unused int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\nSignal %d received, preparing to exit...\n", signum);
- vdpa_sample_quit();
- exit(0);
- }
+ quit = 1;
}
/* interactive cmd functions */
@@ -513,7 +512,7 @@ main(int argc, char *argv[])
}
printf("enter \'q\' to quit\n");
- while (scanf("%c", &ch)) {
+ while (!quit && scanf("%c", &ch)) {
if (ch == 'q')
break;
while (ch != '\n') {
@@ -522,9 +521,10 @@ main(int argc, char *argv[])
}
printf("enter \'q\' to quit\n");
}
- vdpa_sample_quit();
}
+ vdpa_sample_quit();
+
/* clean up the EAL */
rte_eal_cleanup();
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 06/13] examples/vhost: make signal handler safe
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (4 preceding siblings ...)
2026-09-06 23:24 ` [PATCH 05/13] examples/vdpa: make signal handler safe Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-06 23:24 ` [PATCH 07/13] examples/vhost_blk: do not tear down from signal handler Stephen Hemminger
` (8 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Maxime Coquelin, Chenbo Xia
The SIGINT handler unregistered the vhost drivers and called exit(),
neither of which is async-signal-safe.
Set a flag, let switch_worker() return, and unregister the drivers in
main() after joining the lcores.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/vhost/main.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/examples/vhost/main.c b/examples/vhost/main.c
index 5978a50cfe..f768f0c5e0 100644
--- a/examples/vhost/main.c
+++ b/examples/vhost/main.c
@@ -79,6 +79,9 @@ static int dma_count;
/* mask of enabled ports */
static uint32_t enabled_port_mask = 0;
+/* Set by the SIGINT handler to stop the worker loops. */
+static volatile sig_atomic_t quit;
+
/* Promiscuous mode */
static uint32_t promiscuous;
@@ -1494,7 +1497,7 @@ switch_worker(void *arg)
}
}
- while(1) {
+ while (!quit) {
drain_mbuf_table(tx_q);
drain_vhost_table();
/*
@@ -1872,14 +1875,10 @@ unregister_drivers(int socket_num)
}
}
-/* When we receive a INT signal, unregister vhost driver */
static void
sigint_handler(__rte_unused int signum)
{
- /* Unregister vhost driver. */
- unregister_drivers(nb_sockets);
-
- exit(0);
+ quit = 1;
}
static void
@@ -2070,6 +2069,9 @@ main(int argc, char *argv[])
RTE_LCORE_FOREACH_WORKER(lcore_id)
rte_eal_wait_lcore(lcore_id);
+ /* Unregister vhost driver. */
+ unregister_drivers(nb_sockets);
+
for (i = 0; i < dma_count; i++) {
if (rte_vhost_async_dma_unconfigure(dmas_id[i], 0) < 0) {
RTE_LOG(ERR, VHOST_PORT,
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 07/13] examples/vhost_blk: do not tear down from signal handler
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (5 preceding siblings ...)
2026-09-06 23:24 ` [PATCH 06/13] examples/vhost: " Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-06 23:24 ` [PATCH 08/13] examples/ntb: do not print and re-raise " Stephen Hemminger
` (7 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Maxime Coquelin, Chenbo Xia
The SIGINT handler destroyed the controller and called exit() from
signal context.
Set a flag, break the sleep loop, and destroy the controller in main().
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/vhost_blk/vhost_blk.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/examples/vhost_blk/vhost_blk.c b/examples/vhost_blk/vhost_blk.c
index 9c9e326949..0665d9fb51 100644
--- a/examples/vhost_blk/vhost_blk.c
+++ b/examples/vhost_blk/vhost_blk.c
@@ -850,24 +850,18 @@ vhost_blk_ctrlr_destroy(struct vhost_blk_ctrlr *ctrlr)
rte_vhost_driver_unregister(dev_pathname);
}
+/* Set by the SIGINT handler to break the main loop. */
+static volatile sig_atomic_t quit;
+
static void
signal_handler(__rte_unused int signum)
{
- struct vhost_blk_ctrlr *ctrlr;
-
- ctrlr = vhost_blk_ctrlr_find(dev_pathname);
- if (ctrlr == NULL)
- return;
-
- if (ctrlr->started)
- destroy_device(ctrlr->vid);
-
- vhost_blk_ctrlr_destroy(ctrlr);
- exit(0);
+ quit = 1;
}
int main(int argc, char *argv[])
{
+ struct vhost_blk_ctrlr *ctrlr;
int ret;
/* init EAL */
@@ -895,9 +889,17 @@ int main(int argc, char *argv[])
}
/* loop for exit the application */
- while (1)
+ while (!quit)
sleep(1);
+ ctrlr = vhost_blk_ctrlr_find(dev_pathname);
+ if (ctrlr != NULL) {
+ if (ctrlr->started)
+ destroy_device(ctrlr->vid);
+
+ vhost_blk_ctrlr_destroy(ctrlr);
+ }
+
/* clean up the EAL */
rte_eal_cleanup();
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 08/13] examples/ntb: do not print and re-raise from signal handler
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (6 preceding siblings ...)
2026-09-06 23:24 ` [PATCH 07/13] examples/vhost_blk: do not tear down from signal handler Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-06 23:24 ` [PATCH 09/13] examples/ipsecgw: do not print " Stephen Hemminger
` (6 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Jingjing Wu
The handler called printf(), reset the disposition to SIG_DFL and
killed itself, so the process died without stopping the forwarding
lcores or closing the devices.
Set the existing per-lcore stopped flag instead, and mark it volatile
since it is now written from signal context.
SIGINT no longer terminates the application; it stops forwarding and
returns to the ntb> prompt, where quit does the teardown.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/ntb/ntb_fwd.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/examples/ntb/ntb_fwd.c b/examples/ntb/ntb_fwd.c
index 33f3c1ef17..bbacce97db 100644
--- a/examples/ntb/ntb_fwd.c
+++ b/examples/ntb/ntb_fwd.c
@@ -41,7 +41,7 @@ struct ntb_fwd_stream {
struct ntb_fwd_lcore_conf {
uint16_t stream_id;
uint16_t nb_stream;
- uint8_t stopped;
+ volatile uint8_t stopped;
};
enum ntb_fwd_mode {
@@ -947,12 +947,16 @@ prompt(void)
}
static void
-signal_handler(int signum)
+signal_handler(__rte_unused int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\nSignal %d received, preparing to exit...\n", signum);
- signal(signum, SIG_DFL);
- kill(getpid(), signum);
+ struct ntb_fwd_lcore_conf *conf;
+ uint32_t lcore_id;
+
+ RTE_LCORE_FOREACH_WORKER(lcore_id) {
+ conf = &fwd_lcore_conf[lcore_id];
+
+ if (conf->nb_stream)
+ conf->stopped = 1;
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 09/13] examples/ipsecgw: do not print from signal handler
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (7 preceding siblings ...)
2026-09-06 23:24 ` [PATCH 08/13] examples/ntb: do not print and re-raise " Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-08 11:19 ` Radu Nicolau
2026-09-06 23:24 ` [PATCH 10/13] examples/l2fwd-macsec: remove print in " Stephen Hemminger
` (5 subsequent siblings)
14 siblings, 1 reply; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Radu Nicolau, Akhil Goyal
The SIGINT handler calls printf which is not async-signal safe.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/ipsec-secgw/ipsec-secgw.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index eba7560c9b..4816bcdd82 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -2448,11 +2448,8 @@ create_default_ipsec_flow(uint16_t port_id, uint64_t rx_offloads)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
static void
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 10/13] examples/l2fwd-macsec: remove print in signal handler
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (8 preceding siblings ...)
2026-09-06 23:24 ` [PATCH 09/13] examples/ipsecgw: do not print " Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-06 23:24 ` [PATCH 11/13] examples/ethtool: fix exit flag and unchecked cmdline Stephen Hemminger
` (4 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Akhil Goyal
Calling printf in signal handler is not async-signal-safe.
The printf was unnecessary anyway so remove it.
Found by GCC -fanalyzer.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/l2fwd-macsec/main.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/examples/l2fwd-macsec/main.c b/examples/l2fwd-macsec/main.c
index 059f8a2170..33113cb0f5 100644
--- a/examples/l2fwd-macsec/main.c
+++ b/examples/l2fwd-macsec/main.c
@@ -1247,11 +1247,8 @@ check_all_ports_link_status(uint32_t port_mask)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
int
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 11/13] examples/ethtool: fix exit flag and unchecked cmdline
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (9 preceding siblings ...)
2026-09-06 23:24 ` [PATCH 10/13] examples/l2fwd-macsec: remove print in " Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-06 23:24 ` [PATCH 12/13] examples/vmdq_dcb: allow exit on signal Stephen Hemminger
` (3 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, stable, Remy Horton
The exit_now flag is polled by worker_main() on one lcore and set by
main() on another, but is a plain int so the load can be hoisted out
of the loop. Make it volatile.
Also check the cmdline_stdin_new() result before using it.
Found by gcc -fanalyzer.
Fixes: bda68ab9d1e7 ("examples/ethtool: add user-space ethtool sample application")
Cc: stable@dpdk.org
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/ethtool/ethtool-app/ethapp.c | 5 +++++
examples/ethtool/ethtool-app/main.c | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/examples/ethtool/ethtool-app/ethapp.c b/examples/ethtool/ethtool-app/ethapp.c
index 489cd4f515..68c8a29b96 100644
--- a/examples/ethtool/ethtool-app/ethapp.c
+++ b/examples/ethtool/ethtool-app/ethapp.c
@@ -4,6 +4,8 @@
#include <stdlib.h>
+#include <rte_debug.h>
+
#include <cmdline_parse.h>
#include <cmdline_parse_num.h>
#include <cmdline_parse_string.h>
@@ -914,6 +916,9 @@ void ethapp_main(void)
struct cmdline *ctx_cmdline;
ctx_cmdline = cmdline_stdin_new(list_prompt_commands, "EthApp> ");
+ if (ctx_cmdline == NULL)
+ rte_panic("Cannot create cmdline instance\n");
+
cmdline_interact(ctx_cmdline);
cmdline_stdin_exit(ctx_cmdline);
}
diff --git a/examples/ethtool/ethtool-app/main.c b/examples/ethtool/ethtool-app/main.c
index 6545eb322d..ddd256cd7b 100644
--- a/examples/ethtool/ethtool-app/main.c
+++ b/examples/ethtool/ethtool-app/main.c
@@ -44,7 +44,7 @@ struct app_port {
struct app_config {
struct app_port ports[MAX_PORTS];
int cnt_ports;
- int exit_now;
+ volatile int exit_now;
};
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 12/13] examples/vmdq_dcb: allow exit on signal
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (10 preceding siblings ...)
2026-09-06 23:24 ` [PATCH 11/13] examples/ethtool: fix exit flag and unchecked cmdline Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-06 23:24 ` [PATCH 13/13] examples/eventdev_pipeline: make signal handler safe Stephen Hemminger
` (2 subsequent siblings)
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
The forwarding loop never terminated, so the application could only be
killed. There was also no wait for the worker lcores.
Add a SIGINT and SIGTERM handler that sets a flag, return from
lcore_main() when it is set, and join the workers before cleanup.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/vmdq_dcb/main.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/examples/vmdq_dcb/main.c b/examples/vmdq_dcb/main.c
index d6f7b632b9..563b4f9ce1 100644
--- a/examples/vmdq_dcb/main.c
+++ b/examples/vmdq_dcb/main.c
@@ -513,6 +513,15 @@ update_mac_address(struct rte_mbuf *m, unsigned dst_port)
rte_ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->src_addr);
}
+/* Set by the SIGINT and SIGTERM handler to stop the forwarding loops. */
+static volatile sig_atomic_t quit;
+
+static void
+signal_handler(__rte_unused int signum)
+{
+ quit = 1;
+}
+
/* When we receive a HUP signal, print out our stats */
static void
sighup_handler(int signum)
@@ -567,7 +576,7 @@ lcore_main(void *arg)
return 0;
}
- for (;;) {
+ while (!quit) {
struct rte_mbuf *buf[MAX_PKT_BURST];
const uint16_t buf_size = RTE_DIM(buf);
for (p = 0; p < num_ports; p++) {
@@ -598,6 +607,8 @@ lcore_main(void *arg)
}
}
}
+
+ return 0;
}
/*
@@ -640,6 +651,8 @@ main(int argc, char *argv[])
uint16_t portid;
signal(SIGHUP, sighup_handler);
+ signal(SIGINT, signal_handler);
+ signal(SIGTERM, signal_handler);
/* init EAL */
ret = rte_eal_init(argc, argv);
@@ -697,6 +710,11 @@ main(int argc, char *argv[])
/* call on main too */
(void) lcore_main((void*)i);
+ RTE_LCORE_FOREACH_WORKER(lcore_id) {
+ if (rte_eal_wait_lcore(lcore_id) < 0)
+ return -1;
+ }
+
/* clean up the EAL */
rte_eal_cleanup();
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 13/13] examples/eventdev_pipeline: make signal handler safe
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (11 preceding siblings ...)
2026-09-06 23:24 ` [PATCH 12/13] examples/vmdq_dcb: allow exit on signal Stephen Hemminger
@ 2026-09-06 23:24 ` Stephen Hemminger
2026-09-07 9:06 ` [PATCH 00/13] make signal handlers async-signal-safe Bruce Richardson
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
14 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-06 23:24 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
The handler called rte_exit(), rte_event_dev_dump() and (before the
previous patch) printf(), none of which are async-signal-safe.
rte_exit() in particular runs rte_eal_cleanup() and exit(), tearing
down the EAL from signal context while the worker lcores are still
running in it.
Set the done flag and let main() do the work:
- The second-signal path becomes _exit(), which is async-signal-safe.
This keeps the "hit ^C twice to give up on a clean shutdown" escape
hatch without running exit handlers from the handler.
- The --dump-dev dump on exit moves to main() after
rte_eal_mp_wait_lcore(), where it also gets the real dev_id instead
of the hardcoded 0.
- SIGTSTP sets cdata.dump_dev_signal, which schedule_devices() already
checks and drains on the scheduler lcore. That mechanism was present
but nothing ever set the flag. Note this makes the SIGTSTP dump
depend on a scheduler lcore being configured; there is no dump in
configurations without one.
dump_dev_signal is now written from signal context, so make it
volatile sig_atomic_t.
Unlike the rest of this series this one is not reported by
-fanalyzer: the handler is registered in main() after rte_eal_init(),
and the analyzer does not connect the registration to the handler
body there. Found by inspection while auditing the neighbours.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/eventdev_pipeline/main.c | 16 +++++++---------
examples/eventdev_pipeline/pipeline_common.h | 3 ++-
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/examples/eventdev_pipeline/main.c b/examples/eventdev_pipeline/main.c
index 65e0cd437c..80197b7c21 100644
--- a/examples/eventdev_pipeline/main.c
+++ b/examples/eventdev_pipeline/main.c
@@ -314,18 +314,13 @@ do_capability_setup(uint8_t eventdev_id)
static void
signal_handler(int signum)
{
- static uint8_t once;
-
- if (fdata->done)
- rte_exit(1, "Exiting on signal %d\n", signum);
- if ((signum == SIGINT || signum == SIGTERM) && !once) {
- if (cdata.dump_dev)
- rte_event_dev_dump(0, stdout);
- once = 1;
+ if (signum == SIGINT || signum == SIGTERM) {
+ if (fdata->done)
+ _exit(1);
fdata->done = 1;
}
if (signum == SIGTSTP)
- rte_event_dev_dump(0, stdout);
+ cdata.dump_dev_signal = 1;
}
static inline uint64_t
@@ -452,6 +447,9 @@ main(int argc, char **argv)
rte_eal_mp_wait_lcore();
+ if (cdata.dump_dev)
+ rte_event_dev_dump(dev_id, stdout);
+
if (!cdata.quiet && (port_stat(dev_id, worker_data[0].port_id) !=
(uint64_t)-ENOTSUP)) {
printf("\nPort Workload distribution:\n");
diff --git a/examples/eventdev_pipeline/pipeline_common.h b/examples/eventdev_pipeline/pipeline_common.h
index 7b8eb50240..131617cd5b 100644
--- a/examples/eventdev_pipeline/pipeline_common.h
+++ b/examples/eventdev_pipeline/pipeline_common.h
@@ -3,6 +3,7 @@
* Copyright 2017 Cavium, Inc.
*/
+#include <signal.h>
#include <stdbool.h>
#include <rte_eal.h>
@@ -68,7 +69,7 @@ struct config_data {
int enable_queue_priorities;
int quiet;
int dump_dev;
- int dump_dev_signal;
+ volatile sig_atomic_t dump_dev_signal;
int all_type_queues;
unsigned int num_stages;
unsigned int worker_cq_depth;
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH 00/13] make signal handlers async-signal-safe
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (12 preceding siblings ...)
2026-09-06 23:24 ` [PATCH 13/13] examples/eventdev_pipeline: make signal handler safe Stephen Hemminger
@ 2026-09-07 9:06 ` Bruce Richardson
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
14 siblings, 0 replies; 30+ messages in thread
From: Bruce Richardson @ 2026-09-07 9:06 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev
On Sun, Sep 06, 2026 at 04:24:35PM -0700, Stephen Hemminger wrote:
> Signal handlers may only call the functions listed in signal-safety(7).
> Many DPDK examples ignored this and did printf() a "preparing to exit"
> message before setting the quit flag. A signal during another printf
> call can deadlock. And some of the programs did even more
> unsafe things.
>
> GCC 14 -fanalyzer reports these:
>
> warning: call to 'printf' from within signal handler [CWE-479]
> [-Wanalyzer-unsafe-call-within-signal-handler]
>
> The fix is the same throughout: the handler only sets the existing
> volatile flag, and any real work moves to the main loop or to main()
> after the lcores are joined. The message is dropped; the user pressed ^C
> and knows a signal was sent.
>
> Patches 1-2 only delete the printf(). Patches 3-13 also relocate work
> that was being done in the handler.
>
> Behaviour changes worth review:
>
> - examples/ntb: SIGINT used to printf(), restore SIG_DFL and re-raise,
> killing the process without stopping the forwarding lcores or closing
> the devices. It now sets the per-lcore stopped flag, so SIGINT stops
> forwarding and returns to the ntb> prompt; quit does the teardown.
>
> - examples/vdpa: the teardown moved to main() now also closes the vDPA
> devices when leaving interactive mode, which was missing before.
>
> - examples/eventdev_pipeline: the second-signal escape hatch becomes
> _exit() instead of rte_exit(), the --dump-dev exit dump moves to
> main() (and uses the real dev_id rather than a hardcoded 0), and
> SIGTSTP now sets cdata.dump_dev_signal, which schedule_devices()
> already drained but nothing ever set. The SIGTSTP dump therefore
> requires a scheduler lcore.
>
> Only examples/ethtool and examples/vmdq_dcb carry a Fixes: tag; the rest
> remove an unsafe call that has not been seen to deadlock in practice and
> are cleanups rather than backport material.
>
> Applications outside the analyzer's reach likely have the same pattern;
> this covers what GCC flagged, plus eventdev_pipeline found by inspection.
>
> Build tested with GCC 14 -fanalyzer; the warnings are gone for the files
> touched.
>
> Stephen Hemminger (13):
> graph: do not call printf in signal
> examples: remove printf from signal handler
> examples/vmdq: do not print from signal handler
> examples/symmetric_mp: do not print or exit in handler
> examples/vdpa: make signal handler safe
> examples/vhost: make signal handler safe
> examples/vhost_blk: do not tear down from signal handler
> examples/ntb: do not print and re-raise from signal handler
> examples/ipsecgw: do not print from signal handler
> examples/l2fwd-macsec: remove print in signal handler
> examples/ethtool: fix exit flag and unchecked cmdline
> examples/vmdq_dcb: allow exit on signal
> examples/eventdev_pipeline: make signal handler safe
>
Series-Acked-by: Bruce Richardson <bruce.richardson@intel.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v2 00/13] make signal handlers async-signal-safe
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
` (13 preceding siblings ...)
2026-09-07 9:06 ` [PATCH 00/13] make signal handlers async-signal-safe Bruce Richardson
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 01/13] graph: do not call printf in signal Stephen Hemminger
` (12 more replies)
14 siblings, 13 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
Signal handlers may only call the functions listed in signal-safety(7).
Many DPDK examples ignored this and did printf() a "preparing to exit"
message before setting the quit flag. A signal during another printf
call can deadlock. And some of the programs did even more
unsafe things.
GCC 14 -fanalyzer reports these:
warning: call to 'printf' from within signal handler [CWE-479]
[-Wanalyzer-unsafe-call-within-signal-handler]
The fix is the same throughout: the handler only sets the existing
volatile flag, and any real work moves to the main loop or to main()
after the lcores are joined. The message is dropped; the user pressed ^C
and knows a signal was sent.
Patches 1-2 only delete the printf(). Patches 3-13 also relocate work
that was being done in the handler.
Behaviour changes worth review:
- examples/ntb: SIGINT used to printf(), restore SIG_DFL and re-raise,
killing the process without stopping the forwarding lcores or closing
the devices. It now sets the per-lcore stopped flag, so SIGINT stops
forwarding and returns to the ntb> prompt; quit does the teardown.
- examples/vdpa: the teardown moved to main() now also closes the vDPA
devices when leaving interactive mode, which was missing before.
- examples/eventdev_pipeline: the second-signal escape hatch becomes
_exit() instead of rte_exit(), the --dump-dev exit dump moves to
main() (and uses the real dev_id rather than a hardcoded 0), and
SIGTSTP now sets cdata.dump_dev_signal, which schedule_devices()
already drained but nothing ever set. The SIGTSTP dump therefore
requires a scheduler lcore.
Only examples/ethtool and examples/vmdq_dcb carry a Fixes: tag; the rest
remove an unsafe call that has not been seen to deadlock in practice and
are cleanups rather than backport material.
Applications outside the analyzer's reach likely have the same pattern;
this covers what GCC flagged, plus eventdev_pipeline found by inspection.
Build tested with GCC 14 -fanalyzer; the warnings are gone for the files
touched.
v2 -- needed more work, the Claude version of examples_pipeline
was over complex and had build errors.
Stephen Hemminger (13):
graph: do not call printf in signal
examples: remove printf from signal handler
examples/vmdq: do not print from signal handler
examples/symmetric_mp: do not print or exit in handler
examples/vdpa: make signal handler safe
examples/vhost: make signal handler safe
examples/vhost_blk: do not tear down from signal handler
examples/ntb: do not print and re-raise from signal handler
examples/ipsecgw: do not print from signal handler
examples/l2fwd-macsec: remove print in signal handler
examples/ethtool: fix exit flag and unchecked cmdline
examples/vmdq_dcb: allow exit on signal
examples/eventdev_pipeline: make signal handler safe
app/graph/main.c | 4 +-
examples/distributor/main.c | 3 +-
examples/dma/dmafwd.c | 2 -
examples/ethtool/ethtool-app/ethapp.c | 5 +++
examples/ethtool/ethtool-app/main.c | 2 +-
examples/eventdev_pipeline/main.c | 41 ++++++++++++--------
examples/eventdev_pipeline/pipeline_common.h | 13 ++++---
examples/flow_filtering/main.c | 5 +--
examples/ipsec-secgw/ipsec-secgw.c | 5 +--
examples/l2fwd-event/main.c | 5 +--
examples/l2fwd-macsec/main.c | 5 +--
examples/l2fwd/main.c | 5 +--
examples/l3fwd-graph/main.c | 5 +--
examples/multi_process/symmetric_mp/main.c | 26 +++++++++----
examples/ntb/ntb_fwd.c | 16 +++++---
examples/vdpa/main.c | 16 ++++----
examples/vhost/main.c | 14 ++++---
examples/vhost_blk/vhost_blk.c | 26 +++++++------
examples/vmdq/main.c | 20 ++++++++--
examples/vmdq_dcb/main.c | 20 +++++++++-
20 files changed, 140 insertions(+), 98 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v2 01/13] graph: do not call printf in signal
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 02/13] examples: remove printf from signal handler Stephen Hemminger
` (11 subsequent siblings)
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev
Cc: Stephen Hemminger, Bruce Richardson, Sunil Kumar Kori,
Rakesh Kudurumalla
Printf is not signal safe and calling it in a signal handler
get flagged as an error by GCC analyzer.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
app/graph/main.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/app/graph/main.c b/app/graph/main.c
index 56294f2693..d36d60bf94 100644
--- a/app/graph/main.c
+++ b/app/graph/main.c
@@ -49,10 +49,8 @@ static struct app_params {
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n", signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
static int
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 02/13] examples: remove printf from signal handler
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 01/13] graph: do not call printf in signal Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 03/13] examples/vmdq: do not print " Stephen Hemminger
` (10 subsequent siblings)
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev
Cc: Stephen Hemminger, Bruce Richardson, Chengwen Feng, Kevin Laatz,
Ori Kam, Sunil Kumar Kori, Pavan Nikhilesh, Jerin Jacob,
Kiran Kumar K, Nithin Dabilpuram, Zhirun Yan
Printf is not a signal safe function, remove useless printf's
that cause warnings in GCC analyzer.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
examples/distributor/main.c | 3 +--
examples/dma/dmafwd.c | 2 --
examples/eventdev_pipeline/main.c | 2 --
examples/flow_filtering/main.c | 5 +----
examples/l2fwd-event/main.c | 5 +----
examples/l2fwd/main.c | 5 +----
examples/l3fwd-graph/main.c | 5 +----
7 files changed, 5 insertions(+), 22 deletions(-)
diff --git a/examples/distributor/main.c b/examples/distributor/main.c
index ea44939fba..0905482cf0 100644
--- a/examples/distributor/main.c
+++ b/examples/distributor/main.c
@@ -529,9 +529,8 @@ lcore_tx(struct rte_ring *in_r)
}
static void
-int_handler(int sig_num)
+int_handler(int sig_num __rte_unused)
{
- printf("Exiting on signal %d\n", sig_num);
/* set quit flag for rx thread to exit */
quit_signal_rx = 1;
}
diff --git a/examples/dma/dmafwd.c b/examples/dma/dmafwd.c
index a8ed09e6ae..8d195faddb 100644
--- a/examples/dma/dmafwd.c
+++ b/examples/dma/dmafwd.c
@@ -998,8 +998,6 @@ static void
signal_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
force_quit = true;
} else if (signum == SIGUSR1) {
dmadev_dump();
diff --git a/examples/eventdev_pipeline/main.c b/examples/eventdev_pipeline/main.c
index 0c995d1a70..65e0cd437c 100644
--- a/examples/eventdev_pipeline/main.c
+++ b/examples/eventdev_pipeline/main.c
@@ -319,8 +319,6 @@ signal_handler(int signum)
if (fdata->done)
rte_exit(1, "Exiting on signal %d\n", signum);
if ((signum == SIGINT || signum == SIGTERM) && !once) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
if (cdata.dump_dev)
rte_event_dev_dump(0, stdout);
once = 1;
diff --git a/examples/flow_filtering/main.c b/examples/flow_filtering/main.c
index f2124881a0..b4ccaacea1 100644
--- a/examples/flow_filtering/main.c
+++ b/examples/flow_filtering/main.c
@@ -266,11 +266,8 @@ init_port(void)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
/* Parse the argument given in the command line of the application */
diff --git a/examples/l2fwd-event/main.c b/examples/l2fwd-event/main.c
index 2d31d4c6ad..c492c6dee0 100644
--- a/examples/l2fwd-event/main.c
+++ b/examples/l2fwd-event/main.c
@@ -582,11 +582,8 @@ static void
signal_handler(int signum)
{
struct l2fwd_resources *rsrc = l2fwd_get_rsrc();
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
rsrc->force_quit = true;
- }
}
int
diff --git a/examples/l2fwd/main.c b/examples/l2fwd/main.c
index 1c4a89ae90..851816423f 100644
--- a/examples/l2fwd/main.c
+++ b/examples/l2fwd/main.c
@@ -638,11 +638,8 @@ check_all_ports_link_status(uint32_t port_mask)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
int
diff --git a/examples/l3fwd-graph/main.c b/examples/l3fwd-graph/main.c
index 5f89286dce..4fa302f5b0 100644
--- a/examples/l3fwd-graph/main.c
+++ b/examples/l3fwd-graph/main.c
@@ -753,11 +753,8 @@ check_all_ports_link_status(uint32_t port_mask)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
static void
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 03/13] examples/vmdq: do not print from signal handler
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 01/13] graph: do not call printf in signal Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 02/13] examples: remove printf from signal handler Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 04/13] examples/symmetric_mp: do not print or exit in handler Stephen Hemminger
` (9 subsequent siblings)
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson
The SIGHUP handler calls printf() which is not async-signal-safe.
Set a flag instead and print the stats from the main lcore in the
forwarding loop.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
examples/vmdq/main.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/examples/vmdq/main.c b/examples/vmdq/main.c
index 8c9d885090..63ac44deba 100644
--- a/examples/vmdq/main.c
+++ b/examples/vmdq/main.c
@@ -465,18 +465,27 @@ update_mac_address(struct rte_mbuf *m, unsigned dst_port)
rte_ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->src_addr);
}
-/* When we receive a HUP signal, print out our stats */
+/* Set by the SIGHUP handler, consumed by the main lcore. */
+static volatile sig_atomic_t stats_requested;
+
+static void
+sighup_handler(__rte_unused int signum)
+{
+ stats_requested = 1;
+}
+
static void
-sighup_handler(int signum)
+print_stats(void)
{
unsigned int q = vmdq_queue_base;
+
for (; q < num_queues; q++) {
if ((q - vmdq_queue_base) % (num_vmdq_queues / num_pools) == 0)
printf("\nPool %u: ", (q - vmdq_queue_base) /
(num_vmdq_queues / num_pools));
printf("%lu ", rxPackets[q]);
}
- printf("\nFinished handling signal %d\n", signum);
+ putchar('\n');
}
/*
@@ -534,6 +543,11 @@ lcore_main(__rte_unused void *dummy)
struct rte_mbuf *buf[MAX_PKT_BURST];
const uint16_t buf_size = RTE_DIM(buf);
+ if (stats_requested && lcore_id == rte_get_main_lcore()) {
+ stats_requested = 0;
+ print_stats();
+ }
+
for (p = 0; p < num_ports; p++) {
const uint8_t sport = ports[p];
/* 0 <-> 1, 2 <-> 3 etc */
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 04/13] examples/symmetric_mp: do not print or exit in handler
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
` (2 preceding siblings ...)
2026-09-07 17:03 ` [PATCH v2 03/13] examples/vmdq: do not print " Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 05/13] examples/vdpa: make signal handler safe Stephen Hemminger
` (8 subsequent siblings)
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Anatoly Burakov
The SIGINT and SIGTERM handler called printf() and exit() which are
not async-signal-safe.
Set a flag, let the forwarding loops return, and print the stats from
main() after joining the lcores.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
examples/multi_process/symmetric_mp/main.c | 26 ++++++++++++++++------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/examples/multi_process/symmetric_mp/main.c b/examples/multi_process/symmetric_mp/main.c
index 7314a9c6ea..e2d185ab1b 100644
--- a/examples/multi_process/symmetric_mp/main.c
+++ b/examples/multi_process/symmetric_mp/main.c
@@ -92,18 +92,25 @@ smp_usage(const char *prgname, const char *errmsg)
}
-/* signal handler configured for SIGTERM and SIGINT to print stats on exit */
+/* Set by SIGTERM and SIGINT handler to stop the forwarding loops. */
+static volatile sig_atomic_t quit;
+
+static void
+signal_handler(__rte_unused int signum)
+{
+ quit = 1;
+}
+
static void
-print_stats(int signum)
+print_stats(void)
{
unsigned i;
- printf("\nExiting on signal %d\n\n", signum);
+
for (i = 0; i < num_ports; i++){
const uint8_t p_num = ports[i];
printf("Port %u: RX - %u, TX - %u, Drop - %u\n", (unsigned)p_num,
pstats[p_num].rx, pstats[p_num].tx, pstats[p_num].drop);
}
- exit(0);
}
/* Parse the argument given in the command line of the application */
@@ -344,7 +351,7 @@ lcore_main(void *arg __rte_unused)
* queue number corresponding to our process number (not lcore id)
*/
- for (;;) {
+ while (!quit) {
struct rte_mbuf *buf[PKT_BURST];
for (p = start_port; p < end_port; p++) {
@@ -364,6 +371,8 @@ lcore_main(void *arg __rte_unused)
}
}
}
+
+ return 0;
}
/* Check the link status of all ports in up to 9s, and print them finally */
@@ -440,8 +449,8 @@ main(int argc, char **argv)
struct rte_mempool *mp;
/* set up signal handlers to print stats on exit */
- signal(SIGINT, print_stats);
- signal(SIGTERM, print_stats);
+ signal(SIGINT, signal_handler);
+ signal(SIGTERM, signal_handler);
/* initialise the EAL for all */
ret = rte_eal_init(argc, argv);
@@ -484,6 +493,9 @@ main(int argc, char **argv)
RTE_LOG(INFO, APP, "Finished Process Init.\n");
rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MAIN);
+ rte_eal_mp_wait_lcore();
+
+ print_stats();
/* clean up the EAL */
rte_eal_cleanup();
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 05/13] examples/vdpa: make signal handler safe
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
` (3 preceding siblings ...)
2026-09-07 17:03 ` [PATCH v2 04/13] examples/symmetric_mp: do not print or exit in handler Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 06/13] examples/vhost: " Stephen Hemminger
` (7 subsequent siblings)
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Maxime Coquelin, Chenbo Xia
The handler called printf(), the vhost library teardown path and
exit(), none of which are async-signal-safe.
Set a flag and do the teardown in main() once the input loop returns.
This also closes the vDPA devices on exit from interactive mode, which
was missing before.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
examples/vdpa/main.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/examples/vdpa/main.c b/examples/vdpa/main.c
index ac6da79b05..1b989fc6e5 100644
--- a/examples/vdpa/main.c
+++ b/examples/vdpa/main.c
@@ -288,14 +288,13 @@ vdpa_sample_quit(void)
}
}
+/* Set by SIGINT and SIGTERM handler, consumed by main(). */
+static volatile sig_atomic_t quit;
+
static void
-signal_handler(int signum)
+signal_handler(__rte_unused int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\nSignal %d received, preparing to exit...\n", signum);
- vdpa_sample_quit();
- exit(0);
- }
+ quit = 1;
}
/* interactive cmd functions */
@@ -513,7 +512,7 @@ main(int argc, char *argv[])
}
printf("enter \'q\' to quit\n");
- while (scanf("%c", &ch)) {
+ while (!quit && scanf("%c", &ch)) {
if (ch == 'q')
break;
while (ch != '\n') {
@@ -522,9 +521,10 @@ main(int argc, char *argv[])
}
printf("enter \'q\' to quit\n");
}
- vdpa_sample_quit();
}
+ vdpa_sample_quit();
+
/* clean up the EAL */
rte_eal_cleanup();
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 06/13] examples/vhost: make signal handler safe
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
` (4 preceding siblings ...)
2026-09-07 17:03 ` [PATCH v2 05/13] examples/vdpa: make signal handler safe Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 07/13] examples/vhost_blk: do not tear down from signal handler Stephen Hemminger
` (6 subsequent siblings)
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Maxime Coquelin, Chenbo Xia
The SIGINT handler unregistered the vhost drivers and called exit(),
neither of which is async-signal-safe.
Set a flag, let switch_worker() return, and unregister the drivers in
main() after joining the lcores.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
examples/vhost/main.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/examples/vhost/main.c b/examples/vhost/main.c
index 5978a50cfe..f768f0c5e0 100644
--- a/examples/vhost/main.c
+++ b/examples/vhost/main.c
@@ -79,6 +79,9 @@ static int dma_count;
/* mask of enabled ports */
static uint32_t enabled_port_mask = 0;
+/* Set by the SIGINT handler to stop the worker loops. */
+static volatile sig_atomic_t quit;
+
/* Promiscuous mode */
static uint32_t promiscuous;
@@ -1494,7 +1497,7 @@ switch_worker(void *arg)
}
}
- while(1) {
+ while (!quit) {
drain_mbuf_table(tx_q);
drain_vhost_table();
/*
@@ -1872,14 +1875,10 @@ unregister_drivers(int socket_num)
}
}
-/* When we receive a INT signal, unregister vhost driver */
static void
sigint_handler(__rte_unused int signum)
{
- /* Unregister vhost driver. */
- unregister_drivers(nb_sockets);
-
- exit(0);
+ quit = 1;
}
static void
@@ -2070,6 +2069,9 @@ main(int argc, char *argv[])
RTE_LCORE_FOREACH_WORKER(lcore_id)
rte_eal_wait_lcore(lcore_id);
+ /* Unregister vhost driver. */
+ unregister_drivers(nb_sockets);
+
for (i = 0; i < dma_count; i++) {
if (rte_vhost_async_dma_unconfigure(dmas_id[i], 0) < 0) {
RTE_LOG(ERR, VHOST_PORT,
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 07/13] examples/vhost_blk: do not tear down from signal handler
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
` (5 preceding siblings ...)
2026-09-07 17:03 ` [PATCH v2 06/13] examples/vhost: " Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 08/13] examples/ntb: do not print and re-raise " Stephen Hemminger
` (5 subsequent siblings)
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Maxime Coquelin, Chenbo Xia
The SIGINT handler destroyed the controller and called exit() from
signal context.
Set a flag, break the sleep loop, and destroy the controller in main().
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
examples/vhost_blk/vhost_blk.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/examples/vhost_blk/vhost_blk.c b/examples/vhost_blk/vhost_blk.c
index 9c9e326949..0665d9fb51 100644
--- a/examples/vhost_blk/vhost_blk.c
+++ b/examples/vhost_blk/vhost_blk.c
@@ -850,24 +850,18 @@ vhost_blk_ctrlr_destroy(struct vhost_blk_ctrlr *ctrlr)
rte_vhost_driver_unregister(dev_pathname);
}
+/* Set by the SIGINT handler to break the main loop. */
+static volatile sig_atomic_t quit;
+
static void
signal_handler(__rte_unused int signum)
{
- struct vhost_blk_ctrlr *ctrlr;
-
- ctrlr = vhost_blk_ctrlr_find(dev_pathname);
- if (ctrlr == NULL)
- return;
-
- if (ctrlr->started)
- destroy_device(ctrlr->vid);
-
- vhost_blk_ctrlr_destroy(ctrlr);
- exit(0);
+ quit = 1;
}
int main(int argc, char *argv[])
{
+ struct vhost_blk_ctrlr *ctrlr;
int ret;
/* init EAL */
@@ -895,9 +889,17 @@ int main(int argc, char *argv[])
}
/* loop for exit the application */
- while (1)
+ while (!quit)
sleep(1);
+ ctrlr = vhost_blk_ctrlr_find(dev_pathname);
+ if (ctrlr != NULL) {
+ if (ctrlr->started)
+ destroy_device(ctrlr->vid);
+
+ vhost_blk_ctrlr_destroy(ctrlr);
+ }
+
/* clean up the EAL */
rte_eal_cleanup();
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 08/13] examples/ntb: do not print and re-raise from signal handler
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
` (6 preceding siblings ...)
2026-09-07 17:03 ` [PATCH v2 07/13] examples/vhost_blk: do not tear down from signal handler Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 09/13] examples/ipsecgw: do not print " Stephen Hemminger
` (4 subsequent siblings)
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Jingjing Wu
The handler called printf(), reset the disposition to SIG_DFL and
killed itself, so the process died without stopping the forwarding
lcores or closing the devices.
Set the existing per-lcore stopped flag instead, and mark it volatile
since it is now written from signal context.
SIGINT no longer terminates the application; it stops forwarding and
returns to the ntb> prompt, where quit does the teardown.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
examples/ntb/ntb_fwd.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/examples/ntb/ntb_fwd.c b/examples/ntb/ntb_fwd.c
index 33f3c1ef17..bbacce97db 100644
--- a/examples/ntb/ntb_fwd.c
+++ b/examples/ntb/ntb_fwd.c
@@ -41,7 +41,7 @@ struct ntb_fwd_stream {
struct ntb_fwd_lcore_conf {
uint16_t stream_id;
uint16_t nb_stream;
- uint8_t stopped;
+ volatile uint8_t stopped;
};
enum ntb_fwd_mode {
@@ -947,12 +947,16 @@ prompt(void)
}
static void
-signal_handler(int signum)
+signal_handler(__rte_unused int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\nSignal %d received, preparing to exit...\n", signum);
- signal(signum, SIG_DFL);
- kill(getpid(), signum);
+ struct ntb_fwd_lcore_conf *conf;
+ uint32_t lcore_id;
+
+ RTE_LCORE_FOREACH_WORKER(lcore_id) {
+ conf = &fwd_lcore_conf[lcore_id];
+
+ if (conf->nb_stream)
+ conf->stopped = 1;
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 09/13] examples/ipsecgw: do not print from signal handler
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
` (7 preceding siblings ...)
2026-09-07 17:03 ` [PATCH v2 08/13] examples/ntb: do not print and re-raise " Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 10/13] examples/l2fwd-macsec: remove print in " Stephen Hemminger
` (3 subsequent siblings)
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Radu Nicolau, Akhil Goyal
The SIGINT handler calls printf which is not async-signal safe.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
examples/ipsec-secgw/ipsec-secgw.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index eba7560c9b..4816bcdd82 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -2448,11 +2448,8 @@ create_default_ipsec_flow(uint16_t port_id, uint64_t rx_offloads)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
static void
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 10/13] examples/l2fwd-macsec: remove print in signal handler
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
` (8 preceding siblings ...)
2026-09-07 17:03 ` [PATCH v2 09/13] examples/ipsecgw: do not print " Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 11/13] examples/ethtool: fix exit flag and unchecked cmdline Stephen Hemminger
` (2 subsequent siblings)
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Akhil Goyal
Calling printf in signal handler is not async-signal-safe.
The printf was unnecessary anyway so remove it.
Found by GCC -fanalyzer.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
examples/l2fwd-macsec/main.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/examples/l2fwd-macsec/main.c b/examples/l2fwd-macsec/main.c
index 059f8a2170..33113cb0f5 100644
--- a/examples/l2fwd-macsec/main.c
+++ b/examples/l2fwd-macsec/main.c
@@ -1247,11 +1247,8 @@ check_all_ports_link_status(uint32_t port_mask)
static void
signal_handler(int signum)
{
- if (signum == SIGINT || signum == SIGTERM) {
- printf("\n\nSignal %d received, preparing to exit...\n",
- signum);
+ if (signum == SIGINT || signum == SIGTERM)
force_quit = true;
- }
}
int
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 11/13] examples/ethtool: fix exit flag and unchecked cmdline
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
` (9 preceding siblings ...)
2026-09-07 17:03 ` [PATCH v2 10/13] examples/l2fwd-macsec: remove print in " Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 12/13] examples/vmdq_dcb: allow exit on signal Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 13/13] examples/eventdev_pipeline: make signal handler safe Stephen Hemminger
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, stable, Bruce Richardson, Remy Horton
The exit_now flag is polled by worker_main() on one lcore and set by
main() on another, but is a plain int so the load can be hoisted out
of the loop. Make it volatile.
Also check the cmdline_stdin_new() result before using it.
Found by gcc -fanalyzer.
Fixes: bda68ab9d1e7 ("examples/ethtool: add user-space ethtool sample application")
Cc: stable@dpdk.org
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
examples/ethtool/ethtool-app/ethapp.c | 5 +++++
examples/ethtool/ethtool-app/main.c | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/examples/ethtool/ethtool-app/ethapp.c b/examples/ethtool/ethtool-app/ethapp.c
index 489cd4f515..68c8a29b96 100644
--- a/examples/ethtool/ethtool-app/ethapp.c
+++ b/examples/ethtool/ethtool-app/ethapp.c
@@ -4,6 +4,8 @@
#include <stdlib.h>
+#include <rte_debug.h>
+
#include <cmdline_parse.h>
#include <cmdline_parse_num.h>
#include <cmdline_parse_string.h>
@@ -914,6 +916,9 @@ void ethapp_main(void)
struct cmdline *ctx_cmdline;
ctx_cmdline = cmdline_stdin_new(list_prompt_commands, "EthApp> ");
+ if (ctx_cmdline == NULL)
+ rte_panic("Cannot create cmdline instance\n");
+
cmdline_interact(ctx_cmdline);
cmdline_stdin_exit(ctx_cmdline);
}
diff --git a/examples/ethtool/ethtool-app/main.c b/examples/ethtool/ethtool-app/main.c
index 6545eb322d..ddd256cd7b 100644
--- a/examples/ethtool/ethtool-app/main.c
+++ b/examples/ethtool/ethtool-app/main.c
@@ -44,7 +44,7 @@ struct app_port {
struct app_config {
struct app_port ports[MAX_PORTS];
int cnt_ports;
- int exit_now;
+ volatile int exit_now;
};
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 12/13] examples/vmdq_dcb: allow exit on signal
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
` (10 preceding siblings ...)
2026-09-07 17:03 ` [PATCH v2 11/13] examples/ethtool: fix exit flag and unchecked cmdline Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 13/13] examples/eventdev_pipeline: make signal handler safe Stephen Hemminger
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger, Bruce Richardson
The forwarding loop never terminated, so the application could only be
killed. There was also no wait for the worker lcores.
Add a SIGINT and SIGTERM handler that sets a flag, return from
lcore_main() when it is set, and join the workers before cleanup.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
examples/vmdq_dcb/main.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/examples/vmdq_dcb/main.c b/examples/vmdq_dcb/main.c
index d6f7b632b9..563b4f9ce1 100644
--- a/examples/vmdq_dcb/main.c
+++ b/examples/vmdq_dcb/main.c
@@ -513,6 +513,15 @@ update_mac_address(struct rte_mbuf *m, unsigned dst_port)
rte_ether_addr_copy(&vmdq_ports_eth_addr[dst_port], ð->src_addr);
}
+/* Set by the SIGINT and SIGTERM handler to stop the forwarding loops. */
+static volatile sig_atomic_t quit;
+
+static void
+signal_handler(__rte_unused int signum)
+{
+ quit = 1;
+}
+
/* When we receive a HUP signal, print out our stats */
static void
sighup_handler(int signum)
@@ -567,7 +576,7 @@ lcore_main(void *arg)
return 0;
}
- for (;;) {
+ while (!quit) {
struct rte_mbuf *buf[MAX_PKT_BURST];
const uint16_t buf_size = RTE_DIM(buf);
for (p = 0; p < num_ports; p++) {
@@ -598,6 +607,8 @@ lcore_main(void *arg)
}
}
}
+
+ return 0;
}
/*
@@ -640,6 +651,8 @@ main(int argc, char *argv[])
uint16_t portid;
signal(SIGHUP, sighup_handler);
+ signal(SIGINT, signal_handler);
+ signal(SIGTERM, signal_handler);
/* init EAL */
ret = rte_eal_init(argc, argv);
@@ -697,6 +710,11 @@ main(int argc, char *argv[])
/* call on main too */
(void) lcore_main((void*)i);
+ RTE_LCORE_FOREACH_WORKER(lcore_id) {
+ if (rte_eal_wait_lcore(lcore_id) < 0)
+ return -1;
+ }
+
/* clean up the EAL */
rte_eal_cleanup();
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 13/13] examples/eventdev_pipeline: make signal handler safe
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
` (11 preceding siblings ...)
2026-09-07 17:03 ` [PATCH v2 12/13] examples/vmdq_dcb: allow exit on signal Stephen Hemminger
@ 2026-09-07 17:03 ` Stephen Hemminger
12 siblings, 0 replies; 30+ messages in thread
From: Stephen Hemminger @ 2026-09-07 17:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
This example was calling functions like rte_exit and printing from a
signal handler which is not async signal safe.
Revise to spit the two signal actions here:
- The handler for SIGINT and SIGTERM set a flag which causes main
loop to exit and proceed with normal clean shutdown. If a second
SIGINT is received the process will get default signal handler
(i.e process exit).
- The dump flag handler is changed form SIGTSTP (^Z) to use SIGUSR1
since that is more standard practice in Linux.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
examples/eventdev_pipeline/main.c | 39 ++++++++++++--------
examples/eventdev_pipeline/pipeline_common.h | 13 ++++---
2 files changed, 31 insertions(+), 21 deletions(-)
diff --git a/examples/eventdev_pipeline/main.c b/examples/eventdev_pipeline/main.c
index 65e0cd437c..00f409a07b 100644
--- a/examples/eventdev_pipeline/main.c
+++ b/examples/eventdev_pipeline/main.c
@@ -312,20 +312,16 @@ do_capability_setup(uint8_t eventdev_id)
}
static void
-signal_handler(int signum)
+signal_quit(int signum __rte_unused)
{
- static uint8_t once;
-
- if (fdata->done)
- rte_exit(1, "Exiting on signal %d\n", signum);
- if ((signum == SIGINT || signum == SIGTERM) && !once) {
- if (cdata.dump_dev)
- rte_event_dev_dump(0, stdout);
- once = 1;
+ if (fdata != NULL)
fdata->done = 1;
- }
- if (signum == SIGTSTP)
- rte_event_dev_dump(0, stdout);
+}
+
+static void
+signal_dump(int signum __rte_unused)
+{
+ cdata.dump_dev_signal = 1;
}
static inline uint64_t
@@ -345,9 +341,19 @@ main(int argc, char **argv)
int lcore_id;
int err;
- signal(SIGINT, signal_handler);
- signal(SIGTERM, signal_handler);
- signal(SIGTSTP, signal_handler);
+ /* second SIGINT/SIGTERM takes the default action */
+ struct sigaction sa = {
+ .sa_handler = signal_quit,
+ .sa_flags = SA_RESETHAND,
+ };
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+ /* allow repeated dump signals */
+ sa.sa_handler = signal_dump;
+ sa.sa_flags = 0;
+ sigaction(SIGUSR1, &sa, NULL);
err = rte_eal_init(argc, argv);
if (err < 0)
@@ -452,6 +458,9 @@ main(int argc, char **argv)
rte_eal_mp_wait_lcore();
+ if (cdata.dump_dev)
+ rte_event_dev_dump(0, stdout);
+
if (!cdata.quiet && (port_stat(dev_id, worker_data[0].port_id) !=
(uint64_t)-ENOTSUP)) {
printf("\nPort Workload distribution:\n");
diff --git a/examples/eventdev_pipeline/pipeline_common.h b/examples/eventdev_pipeline/pipeline_common.h
index 7b8eb50240..274c6942ca 100644
--- a/examples/eventdev_pipeline/pipeline_common.h
+++ b/examples/eventdev_pipeline/pipeline_common.h
@@ -3,6 +3,7 @@
* Copyright 2017 Cavium, Inc.
*/
+#include <signal.h>
#include <stdbool.h>
#include <rte_eal.h>
@@ -43,7 +44,7 @@ struct setup_data {
};
struct __rte_cache_aligned fastpath_data {
- volatile int done;
+ volatile sig_atomic_t done;
uint32_t evdev_service_id;
uint32_t rxadptr_service_id;
uint32_t txadptr_service_id;
@@ -68,7 +69,7 @@ struct config_data {
int enable_queue_priorities;
int quiet;
int dump_dev;
- int dump_dev_signal;
+ volatile sig_atomic_t dump_dev_signal;
int all_type_queues;
unsigned int num_stages;
unsigned int worker_cq_depth;
@@ -127,16 +128,16 @@ schedule_devices(unsigned int lcore_id)
if (fdata->sched_core[lcore_id]) {
rte_service_run_iter_on_app_lcore(fdata->evdev_service_id,
!fdata->sched_single);
- if (cdata.dump_dev_signal) {
- rte_event_dev_dump(0, stdout);
- cdata.dump_dev_signal = 0;
- }
}
if (fdata->tx_core[lcore_id]) {
rte_service_run_iter_on_app_lcore(fdata->txadptr_service_id,
!fdata->tx_single);
}
+ if (cdata.dump_dev_signal) {
+ rte_event_dev_dump(0, stdout);
+ cdata.dump_dev_signal = 0;
+ }
}
static void
--
2.53.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH 09/13] examples/ipsecgw: do not print from signal handler
2026-09-06 23:24 ` [PATCH 09/13] examples/ipsecgw: do not print " Stephen Hemminger
@ 2026-09-08 11:19 ` Radu Nicolau
0 siblings, 0 replies; 30+ messages in thread
From: Radu Nicolau @ 2026-09-08 11:19 UTC (permalink / raw)
To: Stephen Hemminger, dev; +Cc: Akhil Goyal
On 07-Sep-26 12:24 AM, Stephen Hemminger wrote:
> The SIGINT handler calls printf which is not async-signal safe.
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> examples/ipsec-secgw/ipsec-secgw.c | 5 +----
> 1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
> index eba7560c9b..4816bcdd82 100644
> --- a/examples/ipsec-secgw/ipsec-secgw.c
> +++ b/examples/ipsec-secgw/ipsec-secgw.c
> @@ -2448,11 +2448,8 @@ create_default_ipsec_flow(uint16_t port_id, uint64_t rx_offloads)
> static void
> signal_handler(int signum)
> {
> - if (signum == SIGINT || signum == SIGTERM) {
> - printf("\n\nSignal %d received, preparing to exit...\n",
> - signum);
> + if (signum == SIGINT || signum == SIGTERM)
> force_quit = true;
> - }
> }
>
> static void
I think the same applies to interrupt callbacks (e.g.rte_eth_dev_cb_fn
), many example apps are using printf in those too.
From what I see write() is required to be async signal safe and can be
used instead, in signal handlers and event callbacks, but we will lose
the va args / format specifiers.
https://man7.org/linux/man-pages/man7/signal-safety.7.html
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2026-09-08 11:19 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-06 23:24 [PATCH 00/13] make signal handlers async-signal-safe Stephen Hemminger
2026-09-06 23:24 ` [PATCH 01/13] graph: do not call printf in signal Stephen Hemminger
2026-09-06 23:24 ` [PATCH 02/13] examples: remove printf from signal handler Stephen Hemminger
2026-09-06 23:24 ` [PATCH 03/13] examples/vmdq: do not print " Stephen Hemminger
2026-09-06 23:24 ` [PATCH 04/13] examples/symmetric_mp: do not print or exit in handler Stephen Hemminger
2026-09-06 23:24 ` [PATCH 05/13] examples/vdpa: make signal handler safe Stephen Hemminger
2026-09-06 23:24 ` [PATCH 06/13] examples/vhost: " Stephen Hemminger
2026-09-06 23:24 ` [PATCH 07/13] examples/vhost_blk: do not tear down from signal handler Stephen Hemminger
2026-09-06 23:24 ` [PATCH 08/13] examples/ntb: do not print and re-raise " Stephen Hemminger
2026-09-06 23:24 ` [PATCH 09/13] examples/ipsecgw: do not print " Stephen Hemminger
2026-09-08 11:19 ` Radu Nicolau
2026-09-06 23:24 ` [PATCH 10/13] examples/l2fwd-macsec: remove print in " Stephen Hemminger
2026-09-06 23:24 ` [PATCH 11/13] examples/ethtool: fix exit flag and unchecked cmdline Stephen Hemminger
2026-09-06 23:24 ` [PATCH 12/13] examples/vmdq_dcb: allow exit on signal Stephen Hemminger
2026-09-06 23:24 ` [PATCH 13/13] examples/eventdev_pipeline: make signal handler safe Stephen Hemminger
2026-09-07 9:06 ` [PATCH 00/13] make signal handlers async-signal-safe Bruce Richardson
2026-09-07 17:03 ` [PATCH v2 " Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 01/13] graph: do not call printf in signal Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 02/13] examples: remove printf from signal handler Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 03/13] examples/vmdq: do not print " Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 04/13] examples/symmetric_mp: do not print or exit in handler Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 05/13] examples/vdpa: make signal handler safe Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 06/13] examples/vhost: " Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 07/13] examples/vhost_blk: do not tear down from signal handler Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 08/13] examples/ntb: do not print and re-raise " Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 09/13] examples/ipsecgw: do not print " Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 10/13] examples/l2fwd-macsec: remove print in " Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 11/13] examples/ethtool: fix exit flag and unchecked cmdline Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 12/13] examples/vmdq_dcb: allow exit on signal Stephen Hemminger
2026-09-07 17:03 ` [PATCH v2 13/13] examples/eventdev_pipeline: make signal handler safe Stephen Hemminger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox