Help-Site Computer Manuals
Software
Hardware
Programming
Networking
  Algorithms & Data Structures   Programming Languages   Revision Control
  Protocols
  Cameras   Computers   Displays   Keyboards & Mice   Motherboards   Networking   Printers & Scanners   Storage
  Windows   Linux & Unix   Mac

ChildSafe
control a child process without blocking

ChildSafe - control a child process without blocking


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

  • notify/store/print/ignore
  • Sets the output-handling mode. The meanings of these are described below.

  • cmd
  • Send specified command to child process. Return behavior varies with context:
    array context
    returns a hash containing an array of stdout results (key: 'stdout'), an array of stderr messages ('stderr), and the ``return code'' of the command ('status').

    scalar context
    returns command's ``return code''. In the default mode (NOTIFY), sends stderr results directly to parent's stderr while storing stdout in the object for later retrieval via stdout method. In PRINT mode both stdout and stderr are sent directly to the ``real'' (parent's) stdout/stderr. STORE mode causes both stdout and stderr to be stored for later use, while IGNORE mode throws away both.

    void context
    similar to scalar mode but exits on nonzero return code unless in IGNORE mode.

    void context and no args
    clears the stdout and stderr buffers

  • stdout
  • Return stored output from previous command(s). Behavior varies with context:
    array context
    shifts all stored lines off the stdout stack and returns them in a list.

    scalar context
    returns the number of lines currently stored in the stdout stack.

    void context
    prints the current stdout stack to actual stdout.

  • stderr
  • Similar to stdout method above. Note that by default stderr does not go to the accumulator, but rather to the parent's stderr. Set the STORE attribute to leave stderr in the accumulator instead where this method can operate on it.

  • status
  • Pass the current stdout and stderr buffers to the currently-registered error discriminator and return its results (aka the error count).

  • kill
  • Sends an interrupt signal to the child process. If you've installed a signal handler in the parent using %SIG, you can use ->kill to stop the command currently running in the child from within the handler, then continue to use the child for potential cleanup operations before shutting down.

    A signal other than SIGINT (aka Ctrl-C) may be sent by specifing its name, e.g.

    
    
    
        $child->kill('HUP');

    However, note that signal handling is very complex. The only code path tested is that of SIGINT and other signals may have unpredictable results. Even with SIGINT, a great deal depends on how the tool running as the child process handles it.

  • finish
  • Ends the child process and returns its final exit status.

  • dbglevel
  • Sets a debugging (verbosity) level. Current defined levels are 1-4. Verbosity lines are printed with a leading '+'.

  • noexec
  • Sets the 'noexec' attribute, which causes commands to not be run but to be printed with a leading '-'.


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

Programminig
Wy
Wy
yW
Wy
Programming
Wy
Wy
Wy
Wy