Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with fork exec kill when redirecting output in perl

I created a script in perl to run programs with a timeout. If the program being executed takes longer then the timeout than the script kills this program and returns the message "TIMEOUT".

The script worked quite well until I decided to redirect the output of the executed program.

When the stdout and stderr are being redirected, the program executed by the script is not being killed because it has a pid different than the one I got from fork.

It seems perl executes a shell that executes my program in the case of redirection.

I would like to have the output redirection but still be able to kill the program in the case of a timeout.

Any ideas on how I could do that?

A simplified code of my script is:

#!/usr/bin/perl

use strict;
use warnings;
use POSIX ":sys_wait_h";

my $timeout = 5;
my $cmd = "very_long_program 1>&2 > out.txt";

my $pid = fork();
if( $pid == 0 )
{
   exec($cmd) or print STDERR "Couldn't exec '$cmd': $!";
   exit(2);
}
my $time = 0;
my $kid = waitpid($pid, WNOHANG);
while ( $kid == 0 )
{
   sleep(1);
   $time ++;
   $kid = waitpid($pid, WNOHANG);
   print "Waited $time sec, result $kid\n";
   if ($timeout > 0 && $time > $timeout)
   {
      print "TIMEOUT!\n";
      #Kill process
      kill 9, $pid;
      exit(3);
   }
}

if ( $kid == -1)
{
   print "Process did not exist\n";
   exit(4);
}
print "Process exited with return code $?\n";
exit($?);

Thanks for any help.

like image 494
Edu Avatar asked Jun 03 '10 10:06

Edu


1 Answers

Try changing $cmd from

my $cmd = "very_long_program 1>&2 > out.txt";

to

my $cmd = "exec very_long_program 1>&2 > out.txt";

The exec will tell the shell that gets spawned by perl to replace itself with very_long_program, rather than running very_long_program as a child.

(The reason perl spawns a shell in this case is because $cmd contains the redirect characters - and perl doesn't know how to handle them itself. An alternative way of solving the problem is to do the redirection in perl itself after the fork() but prior to calling exec() - but that's slightly trickier, so try the exec workaround first!)

like image 55
psmears Avatar answered Sep 18 '22 00:09

psmears