Skip to content

innd: also exit promptly on a signal received while busy - #377

Open
go-while wants to merge 3 commits into
InterNetNews:mainfrom
go-while:fix-sigterm-busy
Open

go-while wants to merge 3 commits into
InterNetNews:mainfrom
go-while:fix-sigterm-busy

Conversation

@go-while

Copy link
Copy Markdown

Made with AI (Claude, via Claude Code) under my direction, like #376. Please review it with that in mind.

This is the follow-up announced in #376 and builds on it.
The first two commits are those of #376; the new change is the last commit, bc3424b.

Problem

A SIGTERM or SIGHUP that arrives while innd is busy (not waiting in select()), for instance while a Perl filter_art runs, is blocked by the signal mask.
xsignal_unmask() right before select() then runs the handler, which sets GotTerminate, but select() is not interrupted by it.
innd waits for the whole timeout or the next activity before it reaches the GotTerminate check.

Before signal masking, the handler ran at once but select() waited the same way, so this part is older than the idle case of #376.

Fix

When GotTerminate is set after the unmask, use a zero timeout, so that select() returns at once and the check right after it (moved there by #376) is reached:

xsignal_unmask();
if (GotTerminate) {
    tv.tv_sec = 0;
    tv.tv_usec = 0;
}
count = select(...);

A window of a few instructions between that test and select() remains.
Closing it completely would need pselect() or a self-pipe, which seemed too much here.
The news.pod entry of #376 gets one sentence for this case.

Testing

A Perl filter_innd.pl whose filter_art sleeps, an article fed with IHAVE, SIGTERM during the sleep:

innd result
with #376 only still running 10 s after the signal (and 12 s with a 4 s filter); exits only when something connects
with #376 and this fix exits 0 once the filter returns: 4.1 s with a 3 s filter (3 s filter + the 1 s sleep in JustCleanup())

go-while and others added 3 commits October 23, 2026 15:09
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 termination signal that arrives while innd is not in select() is
blocked by the signal mask.  xsignal_unmask() right before select()
then runs the handler, so select() is not interrupted and innd waits
for the whole timeout (or the next activity) before it checks
GotTerminate.  Before signal masking, the handler ran at once but
select() waited the same way, so this is older than the idle case.

When GotTerminate is set after the unmask, use a zero timeout so that
select() returns at once and the check right after it is reached.  A
window of a few instructions between that test and select() remains;
closing it would need pselect() or a self-pipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Julien-Elie Julien-Elie added bug Something isn't working C: innd Related to innd P: medium Medium priority labels Oct 23, 2026
@Julien-Elie Julien-Elie added this to the 2.7.5 milestone Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working C: innd Related to innd P: medium Medium priority

Development

Successfully merging this pull request may close these issues.

2 participants