v0.x: a signal-ended run dies by its signal¶
A GTB tool stopped by SIGINT, SIGTERM or SIGHUP now drains and then dies by that signal, instead of exiting with
status 128 + signum
(spec 0207).
Nothing in a tool's code changes. What changes is what the process that started it observes.
What changes¶
- A process manager sees a clean stop. systemd counts death by SIGINT, SIGTERM or SIGHUP as success, but did not
count exit status 143, so a unit stopped with
systemctl stopused to endfailed. It no longer does, and aSuccessExitStatus=143line added to work around this can go. Anything reading the wait status (waitpid, Python'ssubprocess, Go'sProcessState) now sees a death by the signal, not exit status 130 or 143. Go'sProcessState.ExitCode()reports-1for it. - A shell's
$?is unchanged: still130after SIGINT and143after SIGTERM, and now129after SIGHUP. A bash script that runs the tool now stops when the tool dies by SIGINT, the way it does for any program interrupted by Ctrl-C. An exit status of 130 did not trigger that. - SIGHUP drains. A command that loses its terminal, for example over a dropped SSH session, now cancels its context and drains like SIGINT, where it used to die at once. Output it writes to that terminal while draining may be lost.
- An inherited ignore stays. A tool started with SIGINT ignored (a background job,
tool &, in a script) or with SIGHUP ignored (nohup) no longer subscribes to that signal, so it no longer drains on it. It used to, because subscribing undid the ignore. SIGTERM is unaffected. - A failed drain is reported. If a command returns an error while draining that is not the cancellation (
nil, or an error wrappingcontext.Canceled), the error is reported like any other failure and the run exits with its code. It used to be discarded in favour of128 + signum. - Windows is unchanged apart from the failed-drain rule: a run interrupted there still exits
128 + signum.
What to check¶
- A test or script that asserts exit status 130 or 143 through a wait status, rather than through a shell's
$?, needs to assert a death by the signal instead. - A command that wraps its cancellation in an error of its own must wrap
context.Canceled(%w), or its stop will read as a failed drain.