Skip Menu |

This queue is for tickets about the Sys-AlarmCall CPAN distribution.

Report information
The Basics
Id: 54122
Status: open
Priority: 0/
Queue: Sys-AlarmCall

People
Owner: Nobody in particular
Requestors: UNERA [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Hi, there! I tried to use Your module, but I was met by the problem: If the function which was given to alarm_call as second parameter uses eval-die blocks and is broken when it does eval block, then alarm_call works incorrectly. Test in atatche showes this problem. You can see the problem if You try print stack in function which uses as $SIG{ALRM} handler. stack will point to broken place. If this place is eval, die from this function will be catched by its eval. I began to try the problem (limit any function by time) and found the solve: we must use "bad" goto statement. Structure of alarm_call must be such this function: sub dtimeout { my ($timeout, $code, @args) = @_; my $prev_alarm = alarm 0; my $start_time = time; my $wantarray = wantarray; # флаг о том что кончилось время на работу my $alarmed; my @res; eval { local $SIG{ALRM} = sub { $alarmed = 1; goto FOO_DONE; }; alarm $timeout; if ($wantarray) { @res = eval { $code->(@args) }; } elsif (defined $wantarray) { $res[0] = eval { $code->(@args) }; } else { eval { $code->(@args) }; } alarm 0; die if $@; }; FOO_DONE: my $e = $@; $e = 'Timeout::alarm' if $alarmed; my $passed_time = time - $start_time; if ($prev_alarm) { if ($passed_time >= $prev_alarm) { kill ALRM => $$; } else { alarm $prev_alarm - $passed_time; } } die $e if $e; return unless defined $wantarray; return @res if $wantarray; return $res[0]; } "bad" goto cleans stack and we can really break the function. above function was got from my code :)
Subject: test.pl
#!/usr/bin/perl use warnings; use strict; use utf8; use open qw(:std :utf8); use Test::More tests => 2; use 5.10.0; BEGIN { use_ok 'Time::HiRes'; use_ok "Sys::AlarmCall"; } sub test_timeout_eval { my @res1 = alarm_call(1, sub { sleep 1.5; sleep 1.5; @_ }, 1, 2, 3); unless ($res1[0] ~~ 'TIMEOUT') { diag "alarm_call didn't break test function"; return 0; } my $time = Time::HiRes::gettimeofday; my @res2 = alarm_call(1, sub { eval { sleep 1.5; }; sleep 1.5; @_ }, 1, 2, 3); $time = Time::HiRes::gettimeofday - $time; unless($res2[0] ~~ 'TIMEOUT') { diag "alarm_call didn't break function with eval, and returned:\n\t" . join("\n\t", @res2) . "\nfunction worked: $time seconds\n"; return 0; } return 1; } ok(test_timeout_eval, "Testing breaking function which uses eval");
Show quoted text
> I began to try the problem (limit any function by time) and found the > solve: we must use "bad" goto statement.
Hgm. "bad goto" doesn't solve this problem, too any ideas?