Repository navigation
Conversation
catch_terminate() only sets GotTerminate, and CHANreadloop() checked it after the select() result: a signal that arrives while innd waits in select() makes it return -1 with EINTR, and the loop went straight back into select(). The signal was only acted on at the next connection or when select() timed out (the remaining part of the timer, up to several minutes), so kill or docker stop usually ended in a SIGKILL without the active file and history being flushed. Check GotTerminate right after select() returns, whatever its result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bug is not limited to innd having no connection: it happens whenever innd waits in select(), with idle connections open too, and also for SIGINT with -d. It was introduced by 9b1b651 (5fa1209 in 2.5.4), which moved the GotTerminate check below the EINTR "continue" so that STATUSmainloophook() could no longer overwrite errno before the EINTR test. The previous commit restores the check before "count < 0" and keeps that errno fix: nothing touches errno unless innd exits. Stopping innd with a signal is what kill does, and what docker and systemd do (followed by SIGKILL after their stop timeout); stopping it with ctlinnd shutdown, as rc.news stop does, was never affected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A small real-world data point for this one, hit by accident today. On one of our test machines (Ubuntu 26.04), two test runs of a build from current main (6843efc, so without this fix) were killed from outside: the test process died and left its Neither innd reacted to SIGTERM; both needed SIGKILL, so neither flushed the active file or history. That's the case this PR fixes: the signal is only acted on when the next connection, data or |
Problem
innd does not shut down when it gets SIGTERM or SIGHUP (or SIGINT with
-d) while it waits inselect().It only acts on the signal at the next connection or data, or when the
timerinterval runs out (ten minutes by default).ctlinnd shutdownandrc.news stopare not affected.Stopping innd by signal is:
kill,docker stop, and systemd's fallback SIGTERM.Docker and systemd then send SIGKILL after their stop timeout, so the active file and history are not flushed.
Reproduce: start
innd -f, wait a moment,kill -TERM <pid>. innd keeps running until something connects.Cause
catch_terminate()only setsGotTerminate. A signal that arrives duringselect()makes it return -1 with EINTR, andCHANreadloop()went straight back intoselect():This order dates from 9b1b651 (5fa1209 in 2.5.4).
That commit moved the
GotTerminatecheck below the EINTR test so thatSTATUSmainloophook()could no longer overwriteerrnofirst.Before it,
GotTerminatewas checked beforecount < 0.Fix
Check
GotTerminateright afterselect()returns, before looking atcount.Julien's errno fix is kept: nothing touches
errnounless innd is exiting.Behaviour on a busy server is unchanged.
The second commit only rewords the
news.podentry (2.7.5 section).Testing
Unpatched and patched innd on Fedora 45, each in a scratch site:
-d, idle, SIGINTThe 1.0 s is the
sleep(1)inJustCleanup(). All shutdowns were clean ("exiting due to signal", no core dumps).make testpasses, and so does thebuildworkflow on my fork.e2ebranch) check idle and loaded shutdown.Related
A signal that arrives while innd is busy (for instance in a slow Perl filter) is blocked until the unmask right before
select().It then interrupts nothing, and innd waits again. That race is older than this bug.
A small follow-up fix with a test is ready on the
fix-sigterm-busybranch;I'll open it once this one is in, or now if you prefer both together.