Charles-Francois Natali <neolo...@free.fr> added the comment:

> 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.

----------
nosy: +neologix

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue8354>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to