in reply to Re: Re: GOTO, Signals and Win32
in thread GOTO, Signals and Win32

Hi. I know this thread is almost 12 years old. I still want to clarify the presented problem for any possible new visitors searching for an answer on the subject.

Your previous code, the one that quits "unexpetedly", has issues, which I comment inline:

foreach $j (@j) { alarm 2; # ^ You shouldn't set an alarm out of the scope where you eval the + time out and localize $SIG{ALRM}; local $SIG{ALRM} = sub { die "timed out" }; # ^ This localization should be inside an eval block so you can ca +tch the alarm. eval { callfc() }; # ^ Here, you are only catching errors from your function, not fro +m a timeout next if $@ and $@ =~ /^timed out$/; # ^ You are checking for the exact string "timed out", but you sho +uld have /^timed out/ (without $ at the end), or, "timed out\n" in bo +th places (including the new-line character) because otherwise the me +ssage will include traces information from "die" }
Now, for your "working" code, which still has issues, I commend inline too:
foreach $j (@j) { print "Next Loop $j \n"; eval { local $SIG{ALRM} = sub { die "Alarm\n"; }; alarm(2); &callfc(); }; # ^ This is much better, you localize $SIG{ALRM} inside eval, and yo +u are also using # the new-line character in the message (and that's why it works (pa +rtially)) # In here, you should have called alarm(0) to cancel the alarm. # It doesn't matter if you are out of the eval block, the alarm cont +inues to run # and you eventually can have an uncatched "timeout" while being on +a different # part of your flow. You must call alarm(0) after your eval block (n +ot from inside # because it can die for a different cause too and never get to the +alarm(0) line). # So, I added it here: alarm 0; if ($@) { die unless $@ eq "Alarm\n"; # ^ You should send the error to the die too so you know what went + wrong, # like this: die $@ unless $@ eq "Alarm\n"; # But yes, you would catch a timeout here (if alarm 0 was present +too above). } else { print "Didnt\n"; } } print "I am continuing with the code\n"; # ^ Yeah... except if you didn't set alarm(0) above, and your script c +ontinues # to run and take longer than the alarm to complete, you'll eventually + have an # error stating "Terminating on signal SIGALRM(14)" and wonder why tha +t happened.
So, to summarize, this is what a timeout block should have, explained:
# First, the thing you want to timeout must be inside of an eval block +: eval { # Second, localize the signal handling and set alarm to the desired +timeout limit: $SIG{ALRM} = sub { die "timeout\n" }; alarm 10; # Third, add the lines of code you specifically want to timeout: do_something_here_that_can_timeout(); }; # Fourth: CANCEL the alarm immediately or you may have problems later! # This should be AFTER the eval block, not inside the eval block: alarm 0; # Fifth: Check for errors to see if you had a timeout or something els +e: if ($@ eq "timeout\n") { # Do whaever you need if a timeout happened handle_timeout(); } else { # You had an actual error and not a timeout, so handle it: handle_error($@); # or just: die $@ }
I hope this helps anyone trying to understand it.

- Zarabozo

Replies are listed 'Best First'.
Re^4: GOTO, Signals and Win32
by LanX (Saint) on Dec 08, 2024 at 21:13 UTC
    > . I know this thread is almost 12 years old.

    Little correction: It's 21 years old. =)

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery