|WARNING| [v2] Revert "examples/symmetric_mp: do not print or exit in handler"
dpdklab at iol.unh.edu
dpdklab at iol.unh.edu
Tue Oct 27 22:14:01 CET 2026
Test-Label: ai-code-review
Test-Status: WARNING
https://dpdk.org/patch/172195
_AI Code Review_
=== Patch Review: series.patch (via Claude) ===
Review date: 2026-10-27
# Review of DPDK Patch: Revert "examples/symmetric_mp: do not print or exit in handler"
## ERRORS
### 1. Signal handler calls exit() directly (forbidden pattern)
**Line:** `exit(0);` in `print_stats()` function
**Issue:** The patch modifies `print_stats()` to be used as a signal handler and calls `exit(0)` directly from it. This is unsafe because `exit()` performs cleanup operations (atexit handlers, stdio flushing, etc.) that are not async-signal-safe. In a multi-process or multi-threaded application, this can deadlock or corrupt state if the signal arrives during malloc, stdio operations, or other non-reentrant code.
**Guideline reference:** "Code that is not safe against signals" under Architecture & Patterns; signal handlers must only call async-signal-safe functions per POSIX.
**Fix:** Use a flag-based approach where the signal handler sets a volatile sig_atomic_t flag, and the main loop checks it:
```c
static volatile sig_atomic_t quit;
static void
signal_handler(int signum __rte_unused)
{
quit = 1;
}
/* In lcore_main */
while (!quit) {
/* ... forwarding loop ... */
}
/* In main after rte_eal_mp_wait_lcore() */
print_stats();
```
This pattern was in the original code before the revert and is the correct approach.
---
### 2. Resource leak: rte_eal_mp_wait_lcore() call removed
**Line:** Removal of `rte_eal_mp_wait_lcore();` before cleanup
**Issue:** The patch removes the `rte_eal_mp_wait_lcore()` call that waits for worker lcores to finish before calling `rte_eal_cleanup()`. Without this, the primary process proceeds directly to cleanup while worker threads are still running their forwarding loops. This is a race condition: `rte_eal_cleanup()` tears down EAL resources (rings, mempools, memory mappings) that the workers are actively using, causing undefined behavior.
**Fix:** Restore the `rte_eal_mp_wait_lcore()` call:
```c
rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MAIN);
rte_eal_mp_wait_lcore();
print_stats();
/* clean up the EAL */
rte_eal_cleanup();
```
---
### 3. lcore_main() unreachable return removed
**Line:** Removal of `return 0;` from `lcore_main()`
**Issue:** The function `lcore_main()` is declared to return `int` (required by `rte_eal_mp_remote_launch()`), but the patch changes the loop to `for (;;)` with no exit condition and removes the `return 0`. This makes the function never return, triggering compiler warnings ("control reaches end of non-void function" or "noreturn function does return") and violating the function signature contract.
**Fix:** Keep the `while (!quit)` loop and `return 0` at the end, as the original code had.
---
### 4. Unused parameter not marked __rte_unused
**Line:** `print_stats(int signum)` function parameter
**Issue:** The `signum` parameter is required by the signal handler signature `void (*)(int)` but is never used in the function body. The v2 commit message says "need to mark arg unused" but the code does not mark it. This will produce a compiler warning.
**Fix:**
```c
static void
print_stats(int signum __rte_unused)
{
/* ... */
}
```
---
## WARNINGS
### 1. Signal handler performs I/O operations (printf)
**Line:** `printf()` calls within `print_stats()` when used as a signal handler
**Issue:** `printf()` is not async-signal-safe. Calling it from a signal handler can deadlock if the signal interrupts another `printf()` or stdio operation, as stdio uses internal locks. While this is noted as "not safe" in the comment, it remains a correctness issue.
**Severity:** Warning (the comment acknowledges this is example code, not production-ready, and the alternative of proper multi-process shutdown is too complex for an example).
**Guideline reference:** "Code that is not safe against signals" under Architecture & Patterns.
---
### 2. Comment describes the problem but does not justify the solution
**Lines:** Comment block above `print_stats()`
**Issue:** The comment correctly states that "This is not safe way to exit for a real production application" and that "proper shutdown with primary/secondary requires process monitoring and rendezvous." However, the code then proceeds to implement an unsafe solution (signal handler calling `exit()` and `printf()`) rather than the safe flag-based approach that was in the original code and does not require complex inter-process monitoring.
**Recommendation:** The original flag-based approach is both safer AND simpler than the reverted version. The justification for reverting should be reconsidered -- the original code's approach (set flag in signal handler, check in loop, wait for workers, then cleanup) is the textbook pattern for handling signals in multi-threaded programs and does not require the "process monitoring and rendezvous" complexity mentioned in the comment.
---
## SUMMARY
The patch introduces multiple correctness bugs by calling unsafe functions (`exit()`, `printf()`) from a signal handler and by removing synchronization (`rte_eal_mp_wait_lcore()`) that prevents races between cleanup and active worker threads. The original code that this patch reverts was architecturally sound; this reversion introduces problems rather than solving them.
The commit message claims the original change caused crashes, but the actual root cause is not addressed here -- the solution should involve proper process coordination, not reverting to unsafe signal handling patterns.
Review-Result: ERROR
More information about the test-report
mailing list