Closed p5pRT closed 13 years ago
When running the code in a $SIG{CHLD} slot\, Perl does the following:
rt_sigprocmask(SIG_BLOCK\, [CHLD]\, NULL\, 8) = 0 rt_sigaction(SIGCHLD\, NULL\, {0x80c5380\, []\, 0}\, 8) = 0 ... { code body here } rt_sigprocmask(SIG_UNBLOCK\, [CHLD]\, NULL\, 8) = 0
My process is running with SIGCHLD blocked (set by POSIX::sigprocmask()); and should receive these signals only during the brief moment the mask is unlocked during a ppoll(2) or epoll_pwait(2) call; not at any other time.
Problem is\, the first time a SIGCHLD is recieved\, the above sequence manages to unblock SIGCHLD again\, meaning the signal could arrive at any time. My $SIG{CHLD} code is written with the assumption that it would only be invoked during such a ppoll(2) call.
Instead\, the mask should be saved by the first call\, and restored by the second; looking something like:
rt_sigprocmask(SIG_BLOCK\, [CHLD]\, [CHLD]\, 8) = 0 rt_sigaction(....) ... { code body here } rt_sigprocmask(SIG_SETMASK\, [CHLD]\, NULL\, 8) = 0
Paul LeoNerd Evans wrote:
Instead\, the mask should be saved by the first call\, and restored by the second; looking something like:
Restore the whole mask? What if you want to change the blocking status of a different signal\, in the body of this signal handler?
-zefram
The RT System itself - Status changed from 'new' to 'open'
On Tue\, Jan 11\, 2011 at 1:23 PM\, Zefram \zefram@​fysh\.org wrote:
Paul LeoNerd Evans wrote: Restore the whole mask? What if you want to change the blocking status of a different signal\, in the body of this signal handler?
How about this?
int was_blocked; sigset_t new\, old;
sigemptyset(&new); sigaddset(&new\, sig);
sigprocmask(SIG_BLOCK\, &new\, &old) = 0; was_blocked = sigismember(&old\, signal); ... { code body here } if (!was_blocked) { sigprocmask(SIG_UNBLOCK\, new\, NULL); }
Signals can't block themselves that way\, but they couldn't do that before either anyway.
Leon
On Tue\, Jan 11\, 2011 at 01:55:34PM +0100\, Leon Timmermans wrote:
On Tue\, Jan 11\, 2011 at 1:23 PM\, Zefram \zefram@​fysh\.org wrote:
Paul LeoNerd Evans wrote: Restore the whole mask? What if you want to change the blocking status of a different signal\, in the body of this signal handler?
Ah\, an excellent point.
How about this?
int was_blocked; sigset_t new\, old;
sigemptyset(&new); sigaddset(&new\, sig);
sigprocmask(SIG_BLOCK\, &new\, &old) = 0; was_blocked = sigismember(&old\, signal); ... { code body here } if (!was_blocked) { sigprocmask(SIG_UNBLOCK\, new\, NULL); }
Signals can't block themselves that way\, but they couldn't do that before either anyway.
That looks much better yes.
Is there a plan for fixing this? Does anyone want to have a stab at fixing it (Leon's suggestion there looks good)\, or should I have a go?
-- Paul "LeoNerd" Evans
leonerd@leonerd.org.uk ICQ# 4135350 | Registered Linux# 179460 http://www.leonerd.org.uk/
On Wed\, Jan 12\, 2011 at 5:23 PM\, Paul LeoNerd Evans \leonerd@​leonerd\.org\.uk wrote:
Is there a plan for fixing this? Does anyone want to have a stab at fixing it (Leon's suggestion there looks good)\, or should I have a go?
I attached a quick patch\, but haven't written tests yet. I've skipped on the PERL_BLOCKSIG_* macro's because quite frankly they weren't helpful at all. Possibly they should be removed\, they aren't used anywhere else in core.
On a related issue\, most uses of sigprocmask (not just this one) should probably be replaced by a macro that uses pthread_sigmask on threaded perls\, as sigprocmask is unspecified in multi-threading applications. This probably requires a probe though.
Leon
On Wed\, Jan 12\, 2011 at 06:45:58PM +0100\, Leon Timmermans wrote:
On Wed\, Jan 12\, 2011 at 5:23 PM\, Paul LeoNerd Evans \leonerd@​leonerd\.org\.uk wrote:
Is there a plan for fixing this? Does anyone want to have a stab at fixing it (Leon's suggestion there looks good)\, or should I have a go?
I attached a quick patch\, but haven't written tests yet. I've skipped on the PERL_BLOCKSIG_* macro's because quite frankly they weren't helpful at all. Possibly they should be removed\, they aren't used anywhere else in core.
They aren't used anywhere else:
$ ack PERL_BLOCKSIG_ `cat ../PERL_BLOCKSIG_ ` Convert-Binary-C/tests/include/perlinc/perl.h 5570:# define PERL_BLOCKSIG_ADD(set\,sig) \ 5572:# define PERL_BLOCKSIG_BLOCK(set) \ 5574:# define PERL_BLOCKSIG_UNBLOCK(set) \ 5580:#ifndef PERL_BLOCKSIG_ADD 5581:# define PERL_BLOCKSIG_ADD(set\, sig) NOOP 5583:#ifndef PERL_BLOCKSIG_BLOCK 5584:# define PERL_BLOCKSIG_BLOCK(set) NOOP 5586:#ifndef PERL_BLOCKSIG_UNBLOCK 5587:# define PERL_BLOCKSIG_UNBLOCK(set) NOOP
perl/mg.c 1379: PERL_BLOCKSIG_ADD(set\, sig); 1381: PERL_BLOCKSIG_BLOCK(set); 1387: PERL_BLOCKSIG_UNBLOCK(set);
perl/perl.h 6026:# define PERL_BLOCKSIG_ADD(set\,sig) \ 6028:# define PERL_BLOCKSIG_BLOCK(set) \ 6030:# define PERL_BLOCKSIG_UNBLOCK(set) \ 6036:#ifndef PERL_BLOCKSIG_ADD 6037:# define PERL_BLOCKSIG_ADD(set\, sig) NOOP 6039:#ifndef PERL_BLOCKSIG_BLOCK 6040:# define PERL_BLOCKSIG_BLOCK(set) NOOP 6042:#ifndef PERL_BLOCKSIG_UNBLOCK 6043:# define PERL_BLOCKSIG_UNBLOCK(set) NOOP
Git blame shows that they were moved to perl.h by 16bd9a85dbc3be76\, having originally been in mg.c in 25da442874cf6136 (its parent).
Reducing levels of indirection (that don't otherwise add anything) good\, in my book.
[I've not really been following the ramifications of the rest of this thread]
Nicholas Clark
On Wed\, Jan 12\, 2011 at 6:45 PM\, Leon Timmermans \fawaka@​gmail\.com wrote:
I attached a quick patch\, but haven't written tests yet. I've skipped on the PERL_BLOCKSIG_* macro's because quite frankly they weren't helpful at all. Possibly they should be removed\, they aren't used anywhere else in core.
I've attached new patches. A fixed version of the previous patch (so it will still build on systems without sigprocmask) and a patch deleting the SIGBLOCK* macros.
Leon
On Thu\, Jan 13\, 2011 at 6:54 PM\, Leon Timmermans \fawaka@​gmail\.com wrote:
I've attached new patches. A fixed version of the previous patch (so it will still build on systems without sigprocmask) and a patch deleting the SIGBLOCK* macros.
Added a few tests. I've never written tests for core before\, so I hope I didn't screw up.
Leon
Improved the tests patch\, and a small documentation update for POSIX::sigprocmask. Unless issues arise\, I think the only thing needed now is a perldelta entry.
Leon
On Mon\, Jan 17\, 2011 at 06:07:06PM +0100\, Leon Timmermans wrote:
Improved the tests patch\, and a small documentation update for POSIX::sigprocmask. Unless issues arise\, I think the only thing needed now is a perldelta entry.
Leon
+ is $gotit\, 0\, 'Haven\'t third received signal yet';
+ is $gotit\, 1\, 'Haven\'t fourth received signal yet';
Those should be:
is $gotit\, 0\, 'Haven\'t received third signal yet';
is $gotit\, 1\, 'Haven\'t received fourth signal yet';
I presume.
Ronald
On Mon\, Jan 17\, 2011 at 8:14 PM\, Ronald J Kimball \rjk@​tamias\.net wrote:
+ is $gotit\, 0\, 'Haven\'t third received signal yet';
+ is $gotit\, 1\, 'Haven\'t fourth received signal yet';
Those should be:
is $gotit\, 0\, 'Haven\'t received third signal yet';
is $gotit\, 1\, 'Haven\'t received fourth signal yet';
I presume.
Yeah\, I evidently wasn't paying attention when I added that :-|
Leon
On Thu Jan 13 09:55:03 2011\, LeonT wrote:
On Wed\, Jan 12\, 2011 at 6:45 PM\, Leon Timmermans \fawaka@​gmail\.com wrote:
I attached a quick patch\, but haven't written tests yet. I've skipped on the PERL_BLOCKSIG_* macro's because quite frankly they weren't helpful at all. Possibly they should be removed\, they aren't used anywhere else in core.
I've attached new patches. A fixed version of the previous patch (so it will still build on systems without sigprocmask) and a patch deleting the SIGBLOCK* macros.
Leon
On Mon Jan 17 09:07:28 2011\, LeonT wrote:
Improved the tests patch\, and a small documentation update for POSIX::sigprocmask. Unless issues arise\, I think the only thing needed now is a perldelta entry.
Leon
Thank you. Applied as:
555344425f04e96a72e4d29eab96b34bff8f96ae f5a55acdcac97456fa66e83ac3d005677b14cc00 0c1bf4c7d433bb0ad80bfe5511b1301db32b7b95 faaf68361923e4bb95d1eb919bc724a0dcc5a4ce
@cpansprout - Status changed from 'open' to 'resolved'
On Wed\, Jan 12\, 2011 at 06:45:58PM +0100\, Leon Timmermans wrote:
I attached a quick patch\, but haven't written tests yet. I've skipped on the PERL_BLOCKSIG_* macro's because quite frankly they weren't helpful at all. Possibly they should be removed\, they aren't used anywhere else in core.
Thanks\, that looks just right for what I had in mind. :)
Now all I have to do is work out a workaround for older perls...
-- Paul "LeoNerd" Evans
leonerd@leonerd.org.uk ICQ# 4135350 | Registered Linux# 179460 http://www.leonerd.org.uk/
On Tue\, Jan 18\, 2011 at 7:34 AM\, Father Chrysostomos via RT \perlbug\-followup@​perl\.org wrote:
Thank you. Applied as:
Seems I missed the special case of a signal handler that throws an exception. Fix and tests are attached.
Leon
On Tue Jan 18 07:43:33 2011\, LeonT wrote:
On Tue\, Jan 18\, 2011 at 7:34 AM\, Father Chrysostomos via RT \perlbug\-followup@​perl\.org wrote:
Thank you. Applied as:
Seems I missed the special case of a signal handler that throws an exception. Fix and tests are attached.
Leon
Thank you. Applied as 7fe50b8.
ribasushi discovered an issue in this patch. It breaks unsafe signal handling. The summary:
When an exception is thrown in a signal handler that results in a call to longjmp. Calling longjmp from a signal handler is undefined per C standard and POSIX (and has a CERT recommendation against it\, SIG32-C). On Linux\, and probably other systems too\, one of the consequences of jumping out of a a signal handler is that the signal mask won't get reset as it should. The previous code compensated for that by always unblocking the signal. Since we can't retroactively forbid exceptions in unsafe signal handlers\, we should solve this differently. We can either
a) Reinstate the old unblocking code for unsafe signals b) Don't block the current signal in the first place\, by using the SA_NODEFER flag in sigaction.
Both behaviors are buggy in my mind\, but hey\, we're talking about unsafe signals so that's all SNAFU.
Leon
On Tue\, Jan 25\, 2011 at 11:11:30PM +0100\, Leon Timmermans wrote:
a) Reinstate the old unblocking code for unsafe signals
Purely from my perspective\, I'd be OK with this one. I wasn't using an unsafe signal; a normal safe one is fine in my case. So I'm less fussed about the behaviour of unsafe ones.
-- Paul "LeoNerd" Evans
leonerd@leonerd.org.uk ICQ# 4135350 | Registered Linux# 179460 http://www.leonerd.org.uk/
On Tue\, Jan 25\, 2011 at 11:11 PM\, Leon Timmermans \fawaka@​gmail\.com wrote:
ribasushi discovered an issue in this patch. It breaks unsafe signal handling. The summary:
When an exception is thrown in a signal handler that results in a call to longjmp. Calling longjmp from a signal handler is undefined per C standard and POSIX (and has a CERT recommendation against it\, SIG32-C). On Linux\, and probably other systems too\, one of the consequences of jumping out of a a signal handler is that the signal mask won't get reset as it should. The previous code compensated for that by always unblocking the signal. Since we can't retroactively forbid exceptions in unsafe signal handlers\, we should solve this differently. We can either
a) Reinstate the old unblocking code for unsafe signals b) Don't block the current signal in the first place\, by using the SA_NODEFER flag in sigaction.
Patch doing option a attached. Not extensively tested though.
Leon
On Sat Feb 12 13:22:51 2011\, LeonT wrote:
On Tue\, Jan 25\, 2011 at 11:11 PM\, Leon Timmermans \fawaka@​gmail\.com wrote:
ribasushi discovered an issue in this patch. It breaks unsafe signal handling. The summary:
When an exception is thrown in a signal handler that results in a call to longjmp. Calling longjmp from a signal handler is undefined per C standard and POSIX (and has a CERT recommendation against it\, SIG32-C). On Linux\, and probably other systems too\, one of the consequences of jumping out of a a signal handler is that the signal mask won't get reset as it should. The previous code compensated for that by always unblocking the signal. Since we can't retroactively forbid exceptions in unsafe signal handlers\, we should solve this differently. We can either
a) Reinstate the old unblocking code for unsafe signals b) Don't block the current signal in the first place\, by using the SA_NODEFER flag in sigaction.
Patch doing option a attached. Not extensively tested though.
Not understanding this area very well (you know it far better than I)\, I do not know how to go about testing it. But I did notice that it does not fix #83646 (Net::Daemon)\, which was broken by the commit in question (7fe50b8). (There could have been something wrong with my setup\, though.)
On Sun\, Feb 13\, 2011 at 10:31 PM\, Father Chrysostomos via RT \perlbug\-followup@​perl\.org wrote:
Not understanding this area very well (you know it far better than I)\, I do not know how to go about testing it.
Here's a new patch that includes a test.
But I did notice that it does not fix #83646 (Net::Daemon)\, which was broken by the commit in question (7fe50b8). (There could have been something wrong with my setup\, though.)
That breakage is due to a bug in that module's unit test\, it's not related to this last patch.
Leon
On Thu Feb 17 10:16:58 2011\, LeonT wrote:
On Sun\, Feb 13\, 2011 at 10:31 PM\, Father Chrysostomos via RT \perlbug\-followup@​perl\.org wrote:
Not understanding this area very well (you know it far better than I)\, I do not know how to go about testing it.
Here's a new patch that includes a test.
But I did notice that it does not fix #83646 (Net::Daemon)\, which was broken by the commit in question (7fe50b8). (There could have been something wrong with my setup\, though.)
That breakage is due to a bug in that module's unit test\, it's not related to this last patch.
Leon
Thank you. I’ve just applied it as c22d665.
Migrated from rt.perl.org#82040 (status was 'resolved')
Searchable as RT82040$