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.
(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") | [reply] [d/l] [select] |
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 | [reply] [d/l] [select] |
(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") | [reply] [d/l] [select] |
|
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.
| [reply] [d/l] [select] |
|
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")
| [reply] [d/l] [select] |
|
|
|
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 | [reply] [d/l] |
|
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.
| [reply] [d/l] |
|
|