Signal handling in objects

S

Stefan Weiss

Hi.

I have a daemon class that needs to handle signals like USR1, USR2, INT,
and TERM depending on the internal state. The way I do it at the moment
is visible in the short demo script below. It works, but I have to admit
that I'm not exactly sure _why_ it works.

Can somebody please explain what happens with that anonymous sub that
gets assigned to $SIG{INT} and $SIG{TERM} in line 22? Where does it take
the value of "$self" from? If it's from the surrounding scope, then how
can it know (later on) that the "running" attribute has changed from 0
to 1? Is this the proper way to do signal handling in an OO context?

TIA,
stefan

------------------------------------------------------------------------
#!/usr/bin/perl

use strict;
use warnings;

my $Daemon = new MyModule;
$Daemon->mainLoop;


package MyModule;

use strict;
use warnings;

sub new {
my $class = shift;
my $obj = {
name => "MyName",
running => 0,
};
my $self = bless $obj, $class;
$SIG{TERM} = $SIG{INT} = sub { $self->handleSignal(shift) };
return $self;
}

sub handleSignal {
my ($self, $sig) = @_;
$self->qlog("info", "caught signal $sig; running: $self->{running}");
$self->qlog("notice", "$self->{name} controlled shutdown");
exit 0;
}

sub qlog {
my ($self, $lvl, $msg) = @_;
print "[$lvl] $msg\n";
}

sub mainLoop {
my $Xself = shift;
$Xself->{running} = 1;
print "in main loop\n";
for (;;) { sleep 1 }
}
 
J

Jeff 'japhy' Pinyan

Can somebody please explain what happens with that anonymous sub that
gets assigned to $SIG{INT} and $SIG{TERM} in line 22? Where does it take
the value of "$self" from? If it's from the surrounding scope, then how
can it know (later on) that the "running" attribute has changed from 0
to 1? Is this the proper way to do signal handling in an OO context?

It is from the surrounding scope; it's called a closure:

my $random_word = do {
my @data = qw( some values of things here );
sub { return $data[rand @data] }
};

Here, @data is a lexical variable visible ONLY inside that do BLOCK where
it is created, and if not for the anonymous subroutine I create and return
and store in $random_word, @data would disappear. However, because the
anonymous subroutine uses a lexical variable, it is a "closure"; plainly
stated, it refers to a lexical variable, and even once that lexical goes
out of scope, it will still have access to its contents.

The code reference in $random_word is the ONLY way of accessing the
contents of @data.
my $self = bless $obj, $class;
$SIG{TERM} = $SIG{INT} = sub { $self->handleSignal(shift) };

That code ref is a closure. The $self it uses is the same $self that you
return from new(), so the object in that code ref is the same object
you're using in the rest of YOUR program.
 
S

Stefan Weiss

Jeff 'japhy' Pinyan said:
That code ref is a closure. The $self it uses is the same $self that you
return from new(), so the object in that code ref is the same object
you're using in the rest of YOUR program.

I knew about the closure, but somehow I had completely overlooked that
$self is of course a hash _reference_, so it's no wonder that another
method can change one of its values, and the signal handler would know
about it. My thought was that $self would be "frozen" inside that
closure, and I would end up with an old copy of the object - but of
course that can't happen with a hash ref.

Sometimes you can't see the forest for the trees, until someone comes
along and happens to mention it. Thanks for your help, that's cleared
it up for me.

cheers,
stefan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,794
Messages
2,569,641
Members
45,354
Latest member
OrenKrause

Latest Threads

Top