in reply to Setting signal handlers considered unsafe?
I couldn't reproduce it under strace
I observed the failure under strace, running on CentOS 5.2 and perl 5.8.8.
I changed the test script, adding a couple of prints in the subroutine and a delay in the child loop. I was interested to see if SIG_DFL was being set on SIGALRM when the parent wasn't being interrupted and it is, every time the subroutine sets its handler, but not when the local %SIG goes out of scope and the original handler is restored.
The modified code:
#!/usr/bin/perl use warnings FATAL => qw( all ); use strict; $|=1; print "setting main handler\n"; $SIG{ALRM} = sub { print "SIGARLM: main handler\n" }; print "set main handler\n"; sub f { print "sub f start\n"; local $SIG{ALRM} = sub { print "SIGALRM: sub handler\n" }; # l +ine 9 print "sub f end\n"; } if (fork) { # parent f while 1; } else { # child sleep 7; print "child starting\n"; sleep 5 while kill ALRM => getppid; }
Strace output while not being interrupted
write(1, "setting main handler\n", 21setting main handler ) = 21 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "set main handler\n", 17set main handler ) = 17 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIG +CHLD, child_tidptr=0xb7f42b08) = 8291 write(1, "sub f start\n", 12sub f start ) = 12 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end ) = 10 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f start\n", 12sub f start ) = 12 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end ) = 10 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f start\n", 12sub f start ) = 12 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end ) = 10 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f start\n", 12sub f start ) = 12 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end
Note that when %SIG{ALRM} is set in the subroutine, sigaction() is called twice, once to set SIGALRM to SIG_DFL and then to set SIGALRM to a handler routine. Then, when the subroutine ends and the local %SIG goes out of scope, sigaction(0 is called only once, setting SIGALRM to the same handler routine. So, SIG_DFL is being set systematically every time you reset the signal handler and this has nothing to do with race conditions in the signal handler as it happens even when no signals have been received. This explains why the signal is sometimes handled by the default handler and the process terminates.
Here is a section of strace output when an alarm was received while the subroutine handler was in place.
rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end ) = 10 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f start\n", 12sub f start ) = 12 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 --- SIGALRM (Alarm clock) @ 0 (0) --- sigreturn() = ? (mask now []) rt_sigprocmask(SIG_BLOCK, [ALRM], NULL, 8) = 0 write(1, "SIGALRM: sub handler\n", 21SIGALRM: sub handler ) = 21 rt_sigprocmask(SIG_UNBLOCK, [ALRM], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end ) = 10 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f start\n", 12sub f start ) = 12 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end
Here is a section of strace output when an alarm was received while the main signal handler was in place.
rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end ) = 10 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 child starting write(1, "sub f start\n", 12sub f start ) = 12 --- SIGALRM (Alarm clock) @ 0 (0) --- sigreturn() = ? (mask now []) rt_sigprocmask(SIG_BLOCK, [ALRM], NULL, 8) = 0 write(1, "SIGARLM: main handler\n", 22SIGARLM: main handler ) = 22 rt_sigprocmask(SIG_UNBLOCK, [ALRM], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end ) = 10 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f start\n", 12sub f start ) = 12 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end
And here is the tail of the strace log when an alarm was received while the default handler was in place.
write(1, "sub f start\n", 12sub f start ) = 12 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end ) = 10 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f start\n", 12sub f start ) = 12 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {SIG_DFL}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f end\n", 10sub f end ) = 10 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {0x713790, [], 0}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 write(1, "sub f start\n", 12sub f start ) = 12 rt_sigprocmask(SIG_BLOCK, [ALRM], [], 8) = 0 rt_sigaction(SIGALRM, {SIG_DFL}, {0x713790, [], 0}, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 --- SIGALRM (Alarm clock) @ 0 (0) --- +++ killed by SIGALRM +++
This behaviour is all quite predictable given that SIGALRM is sometimes set to SIG_DFL.
The question is, why is SIGALRM being set to SIG_DFL then back to perl's signal handler each time the local %SIG is set?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Setting signal handlers considered unsafe?
by gnosek (Sexton) on Nov 05, 2008 at 23:04 UTC | |
|
Re^2: Setting signal handlers considered unsafe? (local assigns undef)
by ikegami (Patriarch) on Nov 09, 2008 at 17:55 UTC |