in reply to Re: Timeout and kill
in thread Timeout and kill

Sorry it's a long script so I was trying to give the portion of code that is the problem. This is the subprocedure:
sub processCnfDirectory { use Time::HiRes(gettimeofday); use File::Basename; my($path) = @_; my $pid; local $SIG{ALRM} = sub { $didTimeout=1; print OUTPUT "timeout"; print "process id", $pid, "\n"; kill 9, $pid; die "Timeout\n"; }; print( "working in: $path\n" ); # append a trailing / if it's not there $path .= '/' if($path !~ /\/$/); # loop through the files contained in the directory for my $file (glob($path . '*')) { # check if the file is a directory if( -d $file) # pass the directory to the routine ( recursion ) processCnfDirectory($file); } elsif ($file =~ /.*\.cnf/) { print OUTPUT basename($file), ","; # run using the first solver $pid = fork; eval { $didTimeout=0; $start1=gettimeofday(); alarm $timeout; #$pid = `$solver1 $file`; $result = `$solver1 $file`; waitpid($pid, 0); }; alarm 0; $end1=gettimeofday(); if($didTimeout == 0) { print OUTPUT $end1 - $start1; } print OUTPUT ","; # run using the second solver $pid = fork; eval { $didTimeout=0; $start2=gettimeofday(); alarm $timeout; #$pid = `$solver2 $file`; $result = `$solver2 $file`; waitpid($pid, 0); }; }; alarm 0; $end2=gettimeofday(); if($didTimeout == 0) { print OUTPUT $end2 - $start2; } print OUTPUT "\n"; } } }
So what it does is it reads in a directory on the command line. It loops through the directory recursively to include subdirectories. Inside a directory it runs a solver on each file. Then it records the amount of time it took to run. The solvers are also command line input.

Replies are listed 'Best First'.
Re^3: Timeout and kill
by onelesd (Pilgrim) on Mar 20, 2012 at 18:40 UTC

    Okay, you still don't need to use fork(). When you use backticks like that, perl runs that command in another process which you can kill - no fork() needed.

    You may want to look at File::Find instead of glob. It makes this kind of thing easier.

      I don't see what you are doing with $result, but one way is to capture the process ID from the shell:

      $pid = `command && echo $$` ;

      I suggest you take a step back and start again with File::Find. I think you've overcomplicated your solution.

      You might also try to prevent the OOM issue in the "solver" instead.

        ...but one way is to capture the process ID from the shell:

        $pid = `command && echo $$` ;

        This wouldn't work.

        First (and least relevant), backticks interpolate the $$, so you'd get the PID of the Perl process here.  But even when fixing this using \$\$, you'd still not get the PID of the command, but that of the shell. And killing the shell does not necessarily also kill the command.  You could in theory try to fix the latter problems by using exec, i.e.

        $pid = `echo \$\$ && exec command` ;

        However, that still wouldn't work, because you wouldn't get at the $pid before the entire backticks command completed.  And in case of a timeout (where you would need the PID primarily), you'd get nothing at all:

        #!/usr/bin/perl -w use strict; my $pid; local $SIG{ALRM} = sub { die "Timeout (pid=$pid)\n"; }; my $command = "perl -e '<>'"; alarm 5; eval { $pid = `echo \$\$ && exec $command`; }; print $@; alarm 0; print "pid=$pid\n"; __END__ Use of uninitialized value $pid in concatenation (.) or string at ./96 +0632.pl line 7. Timeout (pid=) Use of uninitialized value $pid in concatenation (.) or string at ./96 +0632.pl line 18. pid=

        P.S.: contrary to what is implied elsewhere in the thread, alarm does by default not kill the subprocess behind the backticks in case of a timeout — as can easily be verified using ps.

        I took some time to look into File::Find. I had come across this before but it appears I misunderstood it's functionality. Thanks for you help! This has gotten me working on the next part of the problem.
      I was using fork to obtain the pid. How would I obtain the pid without using fork so I can kill it?