Sanjay has asked for the wisdom of the Perl Monks concerning the following question:

eval timeout varies by activity in Perl on Windows.

When OPTION1 in the code below is un-commented, then it times out in 10 seconds every time. Even when run simultaneously in different windows.

OPTION2 is a system call to run a program. It times out in 179 to 182 seconds. When run simultaneously, it times out in 240 to 260 seconds.

All the while the system is (almost) doing nothing apart from this.

CPU & memory both below 100% all through.

I want to have a predictable timeout. A few seconds off is tolerable. An order of magnitude is a severe problem.

Any help appreciated.

use strict; use warnings; my $v_bg_tm = time(); # Just before eval call eval { local %SIG; $SIG{ALRM} = sub { die "Timeout after 10 seconds!\n"; }; alarm 10; # sleep 20; # OPTION 1 - Timeout in 10 seco +nds # `lp_solve lp_Gnrtd-470-Hdr_32.lp`; # OPTION 2 - Timeout in 180+ se +conds alarm 0; }; print time() - $v_bg_tm , " seconds used against timeout of 10 seconds +\n";

Replies are listed 'Best First'.
Re: inconsistent eval timeout (updated)
by haukex (Archbishop) on Oct 31, 2019 at 15:25 UTC

    I'm not sure what's going wrong, but personally I'm not all too surprised there's an issue with signals and alarm on Windows.

    You might want to use a module such as IPC::Run, as it specifically supports timing out the processes it runs (I think this should work on Windows too). There are examples in its documentation and I showed an example here: Re: how to stop command.

    Update: Sorry, I should have tested first. Doesn't seem to work on Windows 7, in my test the process just ran however long it wanted and didn't get interrupted by IPC::Run's timeout.

Re: inconsistent eval timeout
by vr (Curate) on Oct 31, 2019 at 18:48 UTC

    "OPTION 2" doesn't timeout at all, it waits for external command to complete normally. I think because you used backticks instead of system, Perl didn't die in 3 sec but waited until STDOUT of spawned process was closed. This should work:

    use strict; use warnings; my $timeout_msg = "Timeout after 3 seconds!\n"; my $t = time; my $pid; eval { local $SIG{ ALRM } = sub { die $timeout_msg }; alarm 3; $pid = system 1, 'timeout /t 6 > nul && echo Good Morning!'; waitpid $pid, 0; alarm 0 }; if ( $@ ) { die $@ unless $@ eq $timeout_msg; print $@; kill 'KILL', $pid } print time - $t, "\n";

    I hope my use of timeout command won't confuse you to insert it somewhere in your code:), it's just to emulate long-running process. More important is Perl Windows system extension.

      Thanks. Works. However, the job keeps running in the background. Is the kill in the code one of the GNU Windows utilities?

      The & Good Morning! confused me. Why is it there? Presumable a dummy activity, but why?

      Instead of kill, on Windows I found the following more effective

      system("taskkill /F /T /PID $pid");

      The /F to force and the /T for all child processes.

      Please do explain the ... && Good ..., if convenient

        Thanks. Works. However, the job keeps running in the background. Is the kill in the code one of the GNU Windows utilities?

        no, kill is Perl's built-in, used to send any supported signal. Under Win32, it is described to "terminate the process identified by $pid, and make it exit immediately". Apparently, immediate exit is not guaranteed for unresponsive applications, so "taskkill /f" was required in your case.

        The & Good Morning! confused me. Why is it there? Presumable a dummy activity, but why?

        Correct, that "echo" part is kind of dummy; single/double (not important in this case) ampersand is to have several commands on one line, and serves no other purpose but to avoid checking for active tasks. Either I observe a "Good Morining!" even after Perl quit (child shell process was not terminated), or not.

Re: inconsistent eval timeout
by NERDVANA (Priest) on Nov 02, 2019 at 06:20 UTC

    You're trying to use the Unix signal handling model on Windows. Windows doesn't support signals, but Perl tries to provide some compatibility, though it varies depending on which perl you use. Strawberry perl has a lot less support for simulating unix than Cygwin perl does. (and I don't have experience with ActiveState)

    But the first question is what should be expected to happen on Unix. I tested with sleep 20; vs. `sleep 20;`; and it appears that when the alarm goes off, it does not send any signal to the child process, only to the perl script. The child 'sleep' command goes on running which you can observe with ps fax | grep sleep from the terminal. So, assuming you plan was to interrupt the child process, it doesn't work on Unix and definitely won't work on Windows, where signals don't even exist.

    Assuming "lp_solve" is a native windows program, you will need to use the Windows API to run and kill it. Try Proc::Background for a nice wrapper around Win32::Process.

      Thanks. Will try out Proc::Background.
Re: inconsistent eval timeout
by Anonymous Monk on Nov 01, 2019 at 08:25 UTC
    Hi. Background the proc then sleep.