Author neologix
Recipients exarkun, neologix, spiv
Date 2010-04-09.15:16:13
SpamBayes Score 6.14842e-13
Marked as misclassified No
Message-id <1270826175.92.0.433922349878.issue8354@psf.upfronthosting.co.za>
In-reply-to
Content
> The effect of signal.siginterrupt(somesig, False) is reset the first time a that signal is received.  This is not the documented behaviour, and I do not think this is a desireable behaviour.  It renders siginterrupt effectively useless at providing the robustness against EINTR it is intended to provide.

Actually, siginterrupt shouldn't be used.
The proper way is to use sigaction with SA_RESTART flag (and still, don't rely on SA_RESTART too much, certain syscalls are non restartable and this isn't realy portable).

> Another might be to not call PyOS_setsig from signal_handler at all -- I'm not sure why it is trying to reinstall itself, but perhaps there's some issue there I'm not aware of.

Because signal.signal might be implemented with sigaction() or signal() and the latter resets the default signal handler when the handler is called. This means that if your system doesn't support sigaction and and you don't reinstall it, then the handler will only get called the first time.
However, reinstalling the signal handler contains a race, because if a second signal comes before you reinstall it, it's handled by the default handler. That's why sigaction is much better (and calling PyOS_setsig unecessary when sigaction is available).

The problem you describe can happen with both sigaction and signal :

sigaction:
- you set your handler with signal.signal()
- sigaction() is called, and by default syscalls are not restarted (SA_RESTART is false)
- you call siginterrupt() with False, which juste reinstalls the handler with SA_RESTART to true
- the first signal arrives: signal_handler() schedules the call of your handler, and calls PyOS_setsig() 
- PyOS_setsig() reinstalls your handler (again, it's neither a good idea nor necessary with sigaction) _without_ SA_RESTART
- the second signal comes in
- you get a EINTR, game over

signal:
- you set your handler with signal.signal()
- signal() is called, and syscalls are not restarted by default
- you call siginterrupt() with False, which juste reinstalls the handler with SA_RESTART to true
- the first signal arrives: signal_handler() schedules the call of your handler, and calls PyOS_setsig() 
- PyOS_setsig() reinstalles your handler _without_ SA_RESTART (I think the flag is lost even before calling siginterrupt)
- the second signal comes in
- you get a EINTR, game over

So the simple fix when sigaction is available is simply to not call PyOS_setsig() from signal_handler.
When sigaction is not available, well, you have to recall that you want restartable syscalls, and call siginterrupt again with that value. But I think if the OS doesn't support sigaction, there's little chance it'll support siginterrupt.
(1) I just found out that Windows doesn't have sigaction, but I don't know Window much, so if someone could confirm that it doesn't support siginterrupt, then the fix would simply be to not reinstall handler when sigaction is available.
History
Date User Action Args
2010-04-09 15:16:15neologixsetrecipients: + neologix, spiv, exarkun
2010-04-09 15:16:15neologixsetmessageid: <1270826175.92.0.433922349878.issue8354@psf.upfronthosting.co.za>
2010-04-09 15:16:14neologixlinkissue8354 messages
2010-04-09 15:16:13neologixcreate