On 2011-06-16 19:16, C.DeRykus wrote:
Ruud:
C.DeRykus:
Another solution, not necessarily more elegant, but
more familiar to most is an eval {} and alarm pair:
EVAL: {
eval {
local $SIG{ ALRM } = sub { die "alarm"; };
local $SIG{ USR1 } = sub { die "usr1" };
alarm $sleeptime;
... some long running operation here ....
alarm 0;
1;
} or do {
Insert:
my $eval_error = $@ || "Zombie error!";
Huh? If you insert that statement before doing 'alarm 0',
then, there's a potential have a race condition with the
alarm going off and terminating the entire program with
"alarm clock" before you can even check $@.
Realize that the alarm is then already reset (to the earlier setting)
because the localization gets out of scope.
eval { ... ; "foo" happens and sets $@='bar';
...
};
my $eval_error = $@ || "Zombie error!";
# alarm actually does go off now
# and terminates program
alarm 0; # too late
....
Therefore you wouldn't want to insert any statement
before turning off the alarm.
Because the alarm signal is localized (to the eval{}), it is not active
in the do{}.
To support 'nested' alarms (actually more 'in turns' than 'nested'), you
might want to do it like this:
EVAL: {
my $prev_timeout = alarm 0; # stop any outer alarm
my $timeout = 20;
eval {
my $alarm_on = 1;
local $SIG{ ALRM } = sub { die "evalarm" if $alarm_on };
local $SIG{ USR1 } = sub { $alarm_on = 0; die "usr1" };
alarm $timeout;
... some long running operation here (that might die itself) ...
$alarm_on = 0;
alarm $prev_timeout; # re-activate any outer alarm
1; # success
}
or do {
my $eval_error = $@ || "Zombie error!";
alarm $prev_timeout; # re-activate any outer alarm
if ( $eval_error =~ /evalarm/ ) { warn "expired..." }
elsif ( $eval_error =~ /usr1/ ) { redo EVAL }
else { die $eval_error }
};
}
--
Ruud
--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/