[Python-ideas] atexit.register_w_signals()

Chris Angelico rosuav at gmail.com
Fri Feb 12 14:00:25 EST 2016


On Sat, Feb 13, 2016 at 5:36 AM, Giampaolo Rodola' <g.rodola at gmail.com> wrote:
> Also, we would still have to use atexit.register() so that the new function
> is called also on "clean" interpreter exit and take into account other
> signals other than SIGTERM which would cause the process to terminate
> (SIGINT, etc.). My proposal is to evaluate adding a higher-level function
> which takes care of all these details, providing better chances to execute
> the exit function than atexit.register or signal.signal alone.

The trouble is, you can't know which signals will cause a process to
terminate. According to 'man signal', my system has these signals set
to terminate the process by default: HUP, INT, KILL, PIPE, ALRM, TERM,
and USR1/USR2 etc; and these will terminate and dump core: QUIT, ILL,
ABRT, and FPE. Which of them is it correct to register your atexit
handler for? If you get SIGILL or SIGFPE, you can't depend on program
state (they should never be sent to a Python program, so receiving one
almost certainly means an interpreter bug or other major issue).
SIGINT should result in KeyboardInterrupt, so I wouldn't hook that -
let normal exception handling take care of it. SIGHUP, SIGPIPE, and
SIGALRM are often changed in disposition; will you hook them only if
they're on their defaults of terminating the process?

(BTW, the article you link to suggests that Ctrl-D sends SIGQUIT. It
doesn't; what you'll normally get from Ctrl-D is EOF on stdin.)

Ultimately, "exit functions" are a bit of a hairy area to get into,
because so much isn't guaranteed. There's no one best way to ensure
that something happens on termination; just off the top of my head, I
can think of a few ways (on Linux, and most other POSIX systems; no
idea about Windows):

* Create a process that just creates a (some) subprocess(es) and waits
on it (them). When it gets told that its child is dead, it does the
cleanup work (removing a PID file, for instance).

* Divide the process into a client and a server. If the server notices
that the client's missing, it performs an unclean termination cleanup.
(Example: PostgreSQL will roll back your transaction if you disconnect
without committing.)

* Get notified by the system (eg Upstart, SystemD) when the process is
dead, with an event trigger or state trigger.

* Connect to the process via a debugger harness and monitor it for termination.

Not one of these is a perfect solution (they can't use program
internals the way a registered exit function can), but neither is
anything inside the process (for starters, you'll never be able to
handle SIGKILL that way). I'm not sure how useful it is to make a
simple one-liner that claims to make your function run on termination,
but still can't guarantee it; you'll still need to dig into the docs
to figure out exactly what circumstances will and won't cause it to
run.

I agree with Ethan about PyPI though. Give the code a bit of
visibility, see who picks it up.

ChrisA


More information about the Python-ideas mailing list