David Boyce > IPC-ChildSafe-3.16 > IPC::ChildSafe

Download:
IPC-ChildSafe-3.16.tar.gz

Dependencies

Annotate this POD

Related Modules

Net::DNS
more...
By perlmonks.org

CPAN RT

Open  1
View Bugs
Report a bug
Module Version: 3.16   Source  

NAME ^

IPC::ChildSafe, ChildSafe - control a child process without blocking

SYNOPSIS ^

   use IPC::ChildSafe;

   # Start a shell process (create a new shell object).
   $SH = IPC::ChildSafe->new('sh', 'echo ++EOT++', '++EOT++');

   # If the ls command succeeds, read lines from its stdout one at a time.
   if ($SH->cmd('ls') == 0) {
      print "Found ", scalar($SH->stdout), " files in current dir ...\n";

      # Another ls cmd - results added to the object's internal stack
      $SH->cmd('ls /tmp');

      # Since we're stuck in this dumb example, let's get the date too.
      $SH->cmd('date');

      # Now dump results to stdout - show how to get 1 line at a time
      for my $line ($SH->stdout) {
         print $line;
      }

      # You could also print the output this way:
      # print $SH->stdout;

      # Or even just:
      # $SH->stdout;

   }

   # Send it a command, read back the stdout/stderr/return code
   # into a hash array.
   my(%results) = $SH->cmd('id');               # Send an 'id' cmd
   die if $results{status};                     # Expect no errors
   die if @{$results{stdout}} != 1;             # Should be just 1 line
   die if $results{stdout}[0] !~ /^uid=/;       # Check output line

   # (lather, rinse, repeat)

   # Finishing up.
   die if $SH->finish;                          # Returns final status

DESCRIPTION ^

   This was written to address the "blocking problem" inherent in
most coprocessing designs such as IPC::Open3.pm, which has warnings
such as this in its documentation:

    ... additionally, this is very dangerous as you may block forever.  It
   assumes it's going to talk to something like bc, both writing to it and
   reading from it.  This is presumably safe because you "know" that
   commands like bc will read a line at a time and output a line at a
   time ...

or IPC::Open2 which has this warning from its author (Tom Christansen):

   ... I strongly advise against using open2 for almost anything, even
   though I'm its author. UNIX buffering will just drive you up the wall.
   You'll end up quite disappointed ...

The blocking problem is: once you've sent a command to your coprocess, how do you know when the output resulting from this command has finished? If you guess wrong and issue one read too many you can deadlock forever. This implementation solves the problem, at least for a subset of possible child programs, by using a little trick: it sends a 2nd (trivial) command down the pipe right in back of every real command. When we see the the output of this special command in the return pipe, we know the real command is done.

This module also returns an "exit status" for each command, which is really a count of the error messages produced by it. The programmer can optionally register his/her own discriminator function for determining which output to stderr constitutes an error message.

CONSTRUCTOR ^

The constructor takes 3 arguments plus an optional 4th and 5th: the 1st is the program to run, the 2nd is a command to that program which produces a unique one-line output, and the 3rd is that unique output. If a 4th arg is supplied it becomes the mode in which this object will run (default: NOTIFY, see below), and if a 5th is given it must be a code ref, which will be registered as the error discriminator. If no discriminator is supplied then a standard internal one is used.

The 2nd arg is called the "tag command". Preferably this would be something lightweight, e.g. a shell builtin. Unfortunately the current version has no support for a multi-line return value since it would require some fairly complex buffering.

DISCRIMINATOR ^

The discriminator function is invoked after each command completes, and is passed a reference to an array containing the stderr generated by that command in its first parameter. A pointer to the stdout is similarly supplied in the second param. Normally this function would just apply a regular expression to one or both of these and indicate by its return status whether it considers this to constitute an error condition. E.g. the version provided internally is:

    sub errors {
        my($r_stderr, $r_stdout) = @_;
        grep(!/^\+\s|warning:/i, @$r_stderr);
    }

which treats ANY output to stderr as indicative of an error, with the exception of lines beginning with "+ " (shell verbosity) or containing the string "warning:".

METHODS ^

AUTHOR ^

David Boyce dsbperl@cleartool.com

Copyright (c) 1997-2001 David Boyce. All rights reserved. This perl program is free software; you may redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO ^

perl(1), "perldoc IPC::Open3", _Advanced Programming in the Unix Environment_ by W. R. Stevens