shahkinjal
asked on
eval
the following script properly timesout in unix but not in windows OS (both have perl 5.10)
eval
{
$SIG{ALRM} = sub { die "timeout" } ;
alarm 2;
`perl -e "while (1) {}"`;
alarm 0;
};
alarm 0;
if ($@)
{
print "Error = $@";
}
However if i replace `perl -e "while (1) {}"`; with sleep 10
then it works in windows. somehow it doesn't like when the command is executed with backticks on windows
eval
{
$SIG{ALRM} = sub { die "timeout" } ;
alarm 2;
`perl -e "while (1) {}"`;
alarm 0;
};
alarm 0;
if ($@)
{
print "Error = $@";
}
However if i replace `perl -e "while (1) {}"`; with sleep 10
then it works in windows. somehow it doesn't like when the command is executed with backticks on windows
Yes, it looks like You right. Though I don't know why it happens so, I verified that using system() instead of backticks works.
Idles / timeouts are offtenly OS dependant.
use
if (OS == windows) {
1st syntax
} else {
2nd syntax
}
years ago, I used this dummy solution, without messing with couple of OS types
tal
use
if (OS == windows) {
1st syntax
} else {
2nd syntax
}
years ago, I used this dummy solution, without messing with couple of OS types
tal
ASKER
I tried the following (it timeout correctly if my cmd is perl -e sleep 10 but if my command is "perl -v", the output is directly printed to STDOUT . The variable $out is empty which i m printing in the end
$cmd = "perl -v";
eval
{
$SIG{ALRM} = sub { die "timeout" } ;
alarm 2;
$rc = system ("$cmd") ;
$out = <STDOUT>;
alarm 0;
};
alarm 0;
if ($@)
{
print "Error = $@";
}
print "OUT = $out";
$cmd = "perl -v";
eval
{
$SIG{ALRM} = sub { die "timeout" } ;
alarm 2;
$rc = system ("$cmd") ;
$out = <STDOUT>;
alarm 0;
};
alarm 0;
if ($@)
{
print "Error = $@";
}
print "OUT = $out";
You cannot
$out = <STDOUT>;
STDOUT will always give You EOF(it's output only) - that's why the variable is empty.
$out = <STDOUT>;
STDOUT will always give You EOF(it's output only) - that's why the variable is empty.
ASKER
so how can i timeout in windows at the same time return me output if the command does not times out
I'm not following, but did You wanted
> $rc = system ("$cmd") ;
> $out = <STDOUT>;
open(SUB, "$cmd |") ;
$out = <SUB>;
close(SUB);
> $rc = system ("$cmd") ;
> $out = <STDOUT>;
open(SUB, "$cmd |") ;
$out = <SUB>;
close(SUB);
ASKER
This works fine. it return me output and code
$cmd = "perl -v";
eval
{
$SIG{ALRM} = sub { die "timeout" } ;
alarm 2;
open OUT, "$cmd |" or die "$cmd $!";
@output = <OUT>;
close OUT;
$status = $?;
alarm 0;
};
alarm 0;
if ($@)
{
print "Error = $@";
}
print "output = @output \n";
print "code = $status \n";
but this does not time out
$cmd = "perl -e sleep 15";
eval
{
$SIG{ALRM} = sub { die "timeout" } ;
alarm 2;
open OUT, "$cmd |" or die "$cmd $!";
@output = <OUT>;
close OUT;
$status = $?;
alarm 0;
};
alarm 0;
if ($@)
{
print "Error = $@";
}
print "output = @output \n";
print "code = $status \n";
$cmd = "perl -v";
eval
{
$SIG{ALRM} = sub { die "timeout" } ;
alarm 2;
open OUT, "$cmd |" or die "$cmd $!";
@output = <OUT>;
close OUT;
$status = $?;
alarm 0;
};
alarm 0;
if ($@)
{
print "Error = $@";
}
print "output = @output \n";
print "code = $status \n";
but this does not time out
$cmd = "perl -e sleep 15";
eval
{
$SIG{ALRM} = sub { die "timeout" } ;
alarm 2;
open OUT, "$cmd |" or die "$cmd $!";
@output = <OUT>;
close OUT;
$status = $?;
alarm 0;
};
alarm 0;
if ($@)
{
print "Error = $@";
}
print "output = @output \n";
print "code = $status \n";
ASKER
if alarm does not work is there any other alternative way to timeout on windows if the command is executed using backticks
Although I'm not certain, I'm guessing the alarm signal is going to the child, not your process. You could try something like:
eval {
my $start = time();
my $output = '';
open OUT, "$cmd |" or die "$cmd $!";
local $/;
while(<OUT>) {
$output .= $_ ;
die "Timeout\n" if (time() - $start > 2);
}
close OUT;
}
With this, you will only have the possibility of timing out whenever the program outputs some data. So, if you ran "perl -e sleep 10", this would not timeout. But if the program you want to timeout outputs some data regularly, this might work.
The other thing you could do is create a new child thread, and run the program in the child. Then you could terminate that thread after the timeout. I haven't tested this in windows though...
eval {
my $start = time();
my $output = '';
open OUT, "$cmd |" or die "$cmd $!";
local $/;
while(<OUT>) {
$output .= $_ ;
die "Timeout\n" if (time() - $start > 2);
}
close OUT;
}
With this, you will only have the possibility of timing out whenever the program outputs some data. So, if you ran "perl -e sleep 10", this would not timeout. But if the program you want to timeout outputs some data regularly, this might work.
The other thing you could do is create a new child thread, and run the program in the child. Then you could terminate that thread after the timeout. I haven't tested this in windows though...
Windows is not a real operating system in may respects. Perl simulates the aspects associated with threading as well as it can. You have run afoul of that
ASKER
threads seems to work but 1 issue:
the following code properly timeout on WINDOWS but the problem is even the script is completed, the while loop is still running in the system background and i have to manually clean it. can i get the process id and kill it in the script itself?
use threads;
my $pid;
my $child_thread = threads->new(\&my_function );
eval
{
local $SIG{ALRM} = sub { die "timeout" };
alarm 5;
while ( $child_thread->is_running( ) ) { sleep 1; }
alarm 0;
};
alarm 0;
if ($@)
{ print "Timeout: $@ \n";
$child_thread->kill('KILL' )->detach( );
}
sub my_function
{
local $SIG{'KILL'} = sub { threads->exit(); };
`perl -e "while (1) {}"`;
}
the following code properly timeout on WINDOWS but the problem is even the script is completed, the while loop is still running in the system background and i have to manually clean it. can i get the process id and kill it in the script itself?
use threads;
my $pid;
my $child_thread = threads->new(\&my_function
eval
{
local $SIG{ALRM} = sub { die "timeout" };
alarm 5;
while ( $child_thread->is_running(
alarm 0;
};
alarm 0;
if ($@)
{ print "Timeout: $@ \n";
$child_thread->kill('KILL'
}
sub my_function
{
local $SIG{'KILL'} = sub { threads->exit(); };
`perl -e "while (1) {}"`;
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.