Python, signal handlers, and EINTR

August 19, 2009

One of the interesting effects of setting a signal handler in your Python program is, well, let me quote the signal module:

  • When a signal arrives during an I/O operation, it is possible that the I/O operation raises an exception after the signal handler returns. This is dependent on the underlying Unix system's semantics regarding interrupted system calls.

By 'an I/O operation' the manual means more than you might think; for example, select.select() is affected by this. (This is where the whole socket error boondoggle becomes very irritating.)

In general, on Unixes that behave this way, signals that are handled during 'slow' operations (especially IO-related ones) normally cause the system call to fail with an EINTR error. Which system calls this affects and under what circumstances is system dependent, but you generally can count on it affecting at least socket operations, talking to the user's terminal, and things like wait().

(And some system calls don't fail with EINTR but instead return partial results if, for example, they have already transmitted part of your write() on a socket.)

When CPython sees that a system call failed, it raises an exception. It pretty much doesn't do anything special when EINTR is the 'failure' reason; you still get a Python level exception, and it is up to you to notice that this failure is not really a failure and you should retry the operation, assuming that you can and want to.

(There are cases where you cannot; for example, I believe that socket.sendall() can be hit with an EINTR despite having sent some of the buffer, at which point you get an exception instead of a partial result.)

It is my personal feeling that given Python's rich exception handling, your low-level Python code should always retry operations when you get an EINTR-based exception. If a signal handler actually wants to abort or redirect the program, it can easily do this by raising an appropriate exception; in the mean time, your low-level code is in the best position to retry the aborted system call.

Sidebar: EINTR and SA_RESTART

On Unixes that have EINTR, you can usually tell the kernel that you actually don't want your system calls interrupted just because a particular signal handler got called by setting the SA_RESTART flag on the signal handler. Unfortunately, Python does not expose this, even on systems that support it.

Somewhat to my surprise, the GNU libc texinfo documentation has a decent discussion of signals, EINTR, and SA_RESTART.

Written on 19 August 2009.
« Why user programs mapping page zero is so bad news on x86 hardware
Link: Using colour well in data visualization »

Page tools: View Source, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Aug 19 00:47:28 2009
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.