Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Tied %SIG

by bbfu (Curate)
on May 01, 2001 at 00:17 UTC ( [id://76734]=perlquestion: print w/replies, xml ) Need Help??

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

I've been thinking of writing an extension for alarm and $SIG{ALRM} that would grant super powers... er, that is, would let you queue multiple alarms (and handlers), either sequentially, or by shortest-first.

The problem comes in when using this with "legacy" code that sets $SIG{ALRM} itself. As I've got a single, custom alarm handler that should be called every time, if someone sets $SIG{ALRM} manually, it fubar's my whole system.

So, basically, what I need to do is tie the %SIG variable and catch any attempts to set $SIG{ARLM} and execute my own code instead. That's fine, I can do that. My real problem is that, even though my tied STORE method gets called, $SIG{ALRM} is changed to the new value anyway. :-(

Some example code:

#!/usr/bin/perl -w tie %SIG, Foo; alarm(2); $SIG{ALRM} = sub { print "Alarm called!\n" }; sleep 10; package Foo; sub TIEHASH { my $foo = {}; print "Hash tied.\n"; return bless $foo, shift; } sub STORE { return if $REENTRANT; my ($this, $key, $value) = @_; print "Stored $value in \$SIG{$key}.\n"; return unless($key eq 'ALRM'); # Ignore everything but ALRM's ++$REENTRANT; $SIG{ALRM} = sub { print "Ugly Hack(tm) method.\n" }; --$REENTRANT; #$_[1] = sub { print "Parameter change method.\n" }; #return sub { print "Return value method.\n" }; }

The Ugly Hack™ method does work but neither of the other methods do. I'd like to have a more elegant solution, though I'm not sure if one exists.

So, I guess my question is this: Is there another WTDI? I've tried everything I can think of, as well as everything I can find documentation on. I can go with the UH™ method if I have to.

Also, though I understand that it will probably always be relegated to the realm of Deep Magic, does anyone else think that provisions should be made to allow us to tie certain magic Perl variables, such as %SIG, in a relatively straight-forward manner? Or is it generally agreed that doing so would just encourage more madmen to do crazy things?

bbfu
Seasons don't fear The Reaper.
Nor do the wind, the sun, and the rain.
We can be like they are.

Replies are listed 'Best First'.
(tye)Re4: Tied %SIG
by tye (Sage) on May 01, 2001 at 02:21 UTC

    Here is a working example of something that takes control of %SIG so you can insert other code if you like:

    package Sigmund; use base qw( Tie::Hash ); my $realSig= \%::SIG; sub TIEHASH { return bless {}, shift; } sub STORE { my( $self, $key, $value )= @_; my $prev= $realSig->{$key}; # Replace this next line with whatever you like: warn "Changing $key signal handler.\n"; $realSig->{$key}= $value; return $prev; } sub FETCH { my( $self, $key )= @_; return $realSig->{$key}; } *::SIG= {}; tie %::SIG, __PACKAGE__; 1;
    Someone else could even write their own version of this module and whoever's module loaded last would get first crack at changes and any changes from that module would be filtered by the previously loaded module, etc.

            - tye (but my friends call me "Tye")
Re: Tied %SIG
by merlyn (Sage) on May 01, 2001 at 02:43 UTC
    This code I constructed last night while I was chatting with you in the CB shows that even though you can tie %SIG, the "real" setting is still leaking through somewhere, and is the only one that has an effect:
    Buffers Files Tools Edit Search Perl Help + #!/usr/bin/perl -w use strict; $|++; { package MyTie; sub TIEHASH { my $class = shift; my %value; my $self = { value => \%value }; bless $self, $class; warn "blessing $self\n"; # $self->STORE("ALRM", sub { warn "BONG" }); $self; } sub FETCH { my $self = shift; my $key = shift; my $value = $self->{value}->{$key}; warn "$self is fetching $key as $value\n"; $value; } sub STORE { my $self = shift; my $key = shift; my $newvalue = shift; warn "$self is storing $newvalue in $key\n"; $self->{value}->{$key} = $newvalue; } sub DELETE { my $self = shift; my $key = shift; warn "$self is deleting $key\n"; delete $self->{value}->{$key}; } sub CLEAR { my $self = shift; warn "clearing $self\n"; %{$self->{value}} = (); } sub EXISTS { my $self = shift; my $key = shift; warn "checking existance of $key in $self\n"; exists $self->{value}->{$key}; } sub FIRSTKEY { my $self = shift; warn "calling firstkey on $self\n"; my $toss = keys %{$self->{value}}; each %{$self->{value}}; } sub NEXTKEY { my $self = shift; warn "calling nextkey on $self\n"; each %{$self->{value}}; } sub DESTROY { my $self = shift; warn "calling destroy on $self\n"; $self->SUPER::DESTROY; } } tie %::SIG, MyTie::; $SIG{ALRM} = sub { warn "bing!\n" }; alarm(1); select(undef, undef, undef, 3);
    When executed, you get:
    blessing MyTie=HASH(0x80d9290) MyTie=HASH(0x80d9290) is storing CODE(0x80d91e8) in ALRM bing! calling destroy on MyTie=HASH(0x80d9290)
    which shows clearly that the setting of $SIG{ARLM} is both affecting the underlying signal handler and calling the tie STORE operation, but notice at the alarm hit, no corresponding FETCH is called, so the value currently in the private hash would have no effect as it is not consulted.

    Now, uncomment the commented STORE in the early part of the program, and comment out the explicit setting of $SIG{ALRM} at the end, and you get:

    blessing MyTie=HASH(0x80d92ec) MyTie=HASH(0x80d92ec) is storing CODE(0x80d2c30) in ALRM Alarm clock
    which shows again that the tieing of %SIG is apparently not consulted.

    Oh well.

    -- Randal L. Schwartz, Perl hacker

(tye)Re: Tied %SIG
by tye (Sage) on May 01, 2001 at 01:12 UTC

    I can't guess why you think that your other methods should work. STORE methods do not set values by returning a value nor by overwriting the $key parameter.

    Now, if you get anything to work, consider yourself lucky and worry about in what release of Perl it will break. %SIG is magical (yes, that is the real term for it). So when you set values of %SIG, C code inside of Perl gets run in order to set up actual signal handlers. What triggers this C code is called "magic" and you'll have to go read "perldoc perlguts" (and then some) if you want to know more about it.

    If I were going to try this, I'd keep a reference to the original %SIG handy and then replace %SIG with my tied hash:

    my $realSig= \%::SIG; *::SIG= {}; tie %::SIG, ...
    which I have some hope would separate the magic from the tiedness. But I can't offer any guarantees.

    (I don't know if the "::"s are of any use in the above code. The "SIG" is special to Perl such that it knows to always find it in package "main", but I'm not certain that this specialness would always be triggered in the above code so I'm trying not to rely upon it.)

            - tye (but my friends call me "Tye")

      Yeah, I realized that the other methods probably wouldn't work (and wasn't suprised when they didn't) but I thought I'd try them anyway (and included them for completeness).

      I don't want to run afoul of Perl Magic but I don't see how the method that does work (Ugly Hack) could break in the future. Unless, of course, they change it so that the STORE method is never called (ie, you cannot tie %SIG, period). Can you see any reason why it would?

      Personally, it would seem to me that trying to replace %SIG's symbol-table entry would be more likely to break Perl than my method. Thoughts?

      In summary, can you see any reason why I shouldn't go ahead with the method that currently works?

      bbfu
      Seasons don't fear The Reaper.
      Nor do the wind, the sun, and the rain.
      We can be like they are.

        When you tie a hash, attempts to change the hash no longer change the hash, they call a STORE method instead. So I have no reason to believe that your current method should manage to change the underlying, magical %SIG since it all boils down to $SIG{sig}= $codeRef generating a call to STORE that simply returns, doing nothing. In the case of $SIG{ALRM}, you call this STORE method twice, generating the second call to it from within the first call.

        I suspect you have a found a bug in tied variables such that changes to the underlying tied hash leak through when you trigger a second STORE this way (or something similar). This bug probably has other, less desireable effects (like a recent bug where you can't use a different tied variable inside of a STORE method) and so may be fixed and the fix may break your ugly hack.

        If you want to be able to change the original %SIG (in order to invoke the magic), then I really think you need to take steps such that you aren't tieing the original %SIG as changing a hash after it is tied isn't supported. You are relying on undocumented behavior.

        What I suggested relies on documented behaviors. But it is fringe enough that I don't expect the standard test suites and beta testing would always turn up bugs that happen to break the combined behavior.

                - tye (but my friends call me "Tye")
Re: Tied %SIG
by traveler (Parson) on May 01, 2001 at 00:45 UTC
    Maybe I'm missing something, but what is wrong with
    $SIG{$key} = sub { print "Simple Method\n"; };
    --traveler

      I've got %SIG tied, so if I try to do that, it will quickly go recursive on my rear-end. I tried it. :-)

      bbfu
      Seasons don't fear The Reaper.
      Nor do the wind, the sun, and the rain.
      We can be like they are.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://76734]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (4)
As of 2024-04-25 17:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found