in reply to Re: Re: Re: Re: Re: Passing function to a function using \&<function name> method
in thread Passing function to a function using \&<function name> method

Hi edan,

Thanks for this information, it is very useful.

What I have realised is that I would like to take my system call functionality further.

At the moment, the way I have coded it is that the PERL script can gain control back when it has launched an external program/command or script with the system(<command>) or `<command>` method in the event of a timeout.

What I would like to do now is if the timeout is reached, I kill off the process that was launched.

I realised that I would need the PID and am not sure if it would be available from these methods. If the PID is not available from the above methods, what other method can I use to kill off an external program/command or script that PERL has launched once a timeout has reached? Would it be something like a spawn method or something like that?

If there is a Unix only solution to this, then I would still be interested. I mainly to initial testing on Windows, then move onto Red Hat Linux for proper testing and implementation.

Thanks,

Richard Thomas.
  • Comment on Re: Re: Re: Re: Re: Re: Passing function to a function using \&<function name> method

Replies are listed 'Best First'.
Re: Re: Re: Re: Re: Re: Re: Passing function to a function using \&<function name> method
by edan (Curate) on Feb 23, 2004 at 06:11 UTC

    You'll probably want to use fork/exec for this. You'll probably find the perlipc pod useful. Here's a small, very lightly tested example to get you going. Good luck!

    #!/usr/bin/perl -l use strict; use warnings; spawn(5, "/tmp/cmd.pl"); sub spawn { my ($timeout, @cmd) = @_; defined( my $child_pid = fork ) or die "fork: $!"; if ($child_pid) { # parent eval { local $SIG{ALRM} = sub { timeout($child_pid); }; alarm $timeout; waitpid $child_pid, 0; alarm 0; }; if ($@) { print "oops: $@"; } } else { # child exec @cmd or die "exec: $!"; } } sub timeout { my ($pid) = @_; kill 'TERM' => $pid; waitpid $pid, 0; die "reaped $pid\n"; }
    --
    edan (formerly known as 3dan)

      Hi edan,

      Thanks very much for this example code, I have taken it, adapted it a bit and it works exactly how I wanted.

      Thanks again,

      Richard Thomas.
      Hi edan,

      There is just one bit left of what I am trying to do.

      I would like to log the output of the command/program that exec is running.

      I have tried to do this using the >> redirection method as follows:

      $COMMANDLOG is a parameter to turn command logging off or on.
      $LOGNAME is the filename of the file to log to
      if ($COMMANDLOG eq "yes"){ my $LOGTEXT=sprintf("\$%s\n",$cmd); log_list($LOGTEXT); $cmd=sprintf("%s >> %s",$cmd,$LOGNAME); } exec($cmd) or die "exec: $!";
      What happens is that there are two processes running from the exec line and the kill will only kill of the parent of the two processes.

      If command logging is turned off, then there is only one process from the exec line.

      Please could yoe let me know what the best thing to do about this is.

      Thank you.

      Richard Thomas.

        What happens is that there are two processes running from the exec line and the kill will only kill of the parent of the two processes.

        I don't know why a redirection would create 2 processes, but if I wanted to get the output of the child, I would just spawn a child with a filehandle attached, and read it from the parent. I would change the spawn function as follows. WARNING: I haven't tested this at all):

        sub spawn { my ($timeout, @cmd) = @_; defined( my $child_pid = open(CHILD_OUTPUT, "-|" ) or die "fork: $!"; if ($child_pid) { # parent eval { local $SIG{ALRM} = sub { timeout($child_pid); }; alarm $timeout; while (<CHILD_OUTPUT>) { # log it } close(CHILD_OUTPUT) or warn "process $child_pid exited: $? +"; alarm 0; }; if ($@) { print "oops: $@"; } } else { # child exec @cmd or die "exec: $!"; } }
        --
        edan (formerly known as 3dan)