develooper Front page | perl.perl5.porters | Postings from July 2012

Re: [perl #110292] __WARN__ handler disabled if caught signalreceived in this handler

Thread Next
From:
Vincent Lefevre
Date:
July 4, 2012 06:47
Subject:
Re: [perl #110292] __WARN__ handler disabled if caught signalreceived in this handler
Message ID:
20120703082649.GA5727@xvii.vinc17.org
On 2012-06-26 16:52:01 -0700, Jesse Luehrs via RT wrote:
> I'm not sure this is really fixable - this is just how signals work.
> Consider this slight modification of your script:
> 
>   $SIG{__WARN__} = sub {
>       local $SIG{__WARN__} = sub {
>           warn "inner: $_[0]";
>           sleep 2;
>       };
>       warn "outer: $_[0]";
>   };
> 
>   $SIG{USR1} = sub {
>       warn "caught USR1";
>   };
> 
>   $SIG{USR2} = sub {
>       warn "caught USR2";
>   };
> 
>   if (my $pid = fork) {
>       kill USR1 => $pid;
>       sleep 1;
>       kill USR2 => $pid;
>       wait;
>   }
>   else {
>       sleep 5;
>   }
> 
> This prints:
> 
>   inner: outer: caught USR1 at test.pl line 14.
>   caught USR2 at test.pl line 18.
> 
> Do you think the second warning should be "inner: outer: caught USR2" or
> "inner: caught USR2"?

Here this is a bit particular because of the "local". I don't think
that code executed in a signal handler should be affected by a local
(dynamic) variable that has been set outside the handler execution,
otherwise one could get obscure side effects. For instance, consider

#!/usr/bin/env perl

$SIG{USR1} = sub {
  open FILE, "/etc/crontab" or die;
  my $line = <FILE>;
  print $line;
  close FILE or die;
  exit;
};

print "$$\n";
my $file = do { local $/; <STDIN> };
print $file;

The current behavior when the USR1 signal is received in the do block
is that /etc/crontab is printed entirely. I don't think this is what
the user expects. Also remember that modules may also use local() for
internal implementation, so that handlers written by a user may not
be reliable if they depend on Perl variables.

So, in your example, for USR2,

sub {
      local $SIG{__WARN__} = sub {
          warn "inner: $_[0]";
          sleep 2;
      };
      warn "outer: $_[0]";
  };

should be executed and give "inner: outer: caught USR2".

> How do you determine which warn handler to restore during the
> execution of the signal?

The global one should be restored (more generally, any local should
lose its effect, as if it never occurred).

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About