pileofrogs has asked for the wisdom of the Perl Monks concerning the following question:

Is there a way to pass data to a signal handler without using globals? Here's a simplistic example using globals, and I wonder if there's a way to do this without globals.
my $feeling = 'happy'; $SIG{INT} = \&handler; sub handler { warn "I feel ".$feeling."\n"; exit; } # do some stuff $feeling = 'sleepy'; # do some other stuff $feeling = 'grumpy';

Replies are listed 'Best First'.
Re: getting data to a signal handler
by Zaxo (Archbishop) on Nov 19, 2005 at 01:23 UTC

    We're stuck with globals for that. The only argument a handler gets is the name of the signal that fired it.

    Since we don't know where in the code a handler will fire, only global variables can be relied on to be visible to the handler. It's best if they are not file-level lexicals. That produces a closure with the handlers which use them, occasionally producing hard-to-debug "features".

    Added: The first section of your local perlipc is on signal handling, and is full of great tips and tricks.

    After Compline,
    Zaxo

      I figured out something that doesn't SEEM to use globals, but it probably does something much worse...

      Run this and hit CTRL-C, it will print how many seconds it thinks it's been running

      #! /usr/bin/perl -w -T use strict; my $var; ($var,$SIG{INT}) = voodoo(); sub voodoo { my $thing ; my $sub = sub { my $blob = \$thing; print $$blob."\n"; exit; }; return (\$thing,$sub); } for (my $i=0; $i<60 ;$i++) { $$var = $i; sleep 1; }

      Let me know what sort of terrible thing I've done...

        You're forming a closure on $thing, as well as returning a reference to it. voodoo() indeed!

        One nice way to pretend you don't have a global variable when you do (I've talked about this one before):

        { my $foo; sub foo () :lvalue { $foo } } foo = 'bar'; print foo, $/;
        No sigil, that makes some people happy ;-)

        After Compline,
        Zaxo

        In general, lexical closures are a handy and useful technique, but I'm not entirely sure what interesting edge cases will emerge if you combine them with signal handlers. I wouldn't care to speculate on that without understanding the nittier and grittier details of how signal handlers are handled.

        What I would do is name the global in a fashion that prevents it from ever having a namespace collision and then just leave it global. For instance, I might call it something like $SIGINT_HANDLER_GLOBAL_ONE_FOR_NET_SERVER_POP3 (if it were the first global variable for the interrupt signal handler for Net::Server::POP3; as it happens that module doesn't have any such thing, but you get the idea).