#include <Iguana/Utilities/classlib/iobase/SubProcess.h>
Public Types | |
enum | Flags { Read = 1, Write = 2, First = 4, Last = 8, One = First | Last, Synchronous = 16, Search = 32, NoCloseInput = 64, NoCloseOutput = 128 } |
Public Member Functions | |
virtual void | detach (void) |
virtual bool | done (void) |
virtual IOChannel * | input (void) const |
virtual IOChannel * | output (void) const |
virtual pid_t | pid (void) const |
virtual Pipe * | pipe (void) const |
virtual pid_t | run (const char **argz, unsigned flags, IOChannel *input, IOChannel *output=0) |
virtual pid_t | run (const char **argz, unsigned flags, SubProcess *input, IOChannel *output=0) |
virtual pid_t | run (const char **argz, unsigned flags, Pipe *pipe, IOChannel *other=0) |
virtual pid_t | run (const char **argz, unsigned flags=One) |
SubProcess (const char **argz, unsigned flags, IOChannel *input, IOChannel *output=0) | |
SubProcess (const char **argz, unsigned flags, SubProcess *input, IOChannel *output=0) | |
SubProcess (const char **argz, unsigned flags, Pipe *pipe, IOChannel *other=0) | |
SubProcess (const char **argz, unsigned flags=One) | |
SubProcess (void) | |
virtual void | terminate (void) |
virtual int | wait (void) |
virtual | ~SubProcess (void) |
Static Public Member Functions | |
static bool | exitBySignal (int waitcode) |
static bool | exitNormal (int waitcode) |
static int | exitSignal (int waitcode) |
static int | exitStatus (int waitcode) |
Private Member Functions | |
pid_t | dorun (const char **argz, unsigned flags, IOChannel *input, IOChannel *output, IOChannel *cleanup) |
SubProcess & | operator= (const SubProcess &x) |
SubProcess (const SubProcess &x) | |
void | sysdetach (void) |
pid_t | sysrun (const char **argz, unsigned flags, IOChannel *input, IOChannel *output, IOChannel *cleanup) |
Private Attributes | |
IOChannel * | m_input |
IOChannel * | m_output |
Pipe * | m_pipe |
int | m_status |
pid_t | m_sub |
This class provides a convenient interface for running commands in subprocesses with possibly redirected input and output. One can run either simple subcommands, or entire subprocess pipelines. The entire pipeline (henceforth "subprocess chain") can have its input or output redirected to or from a pipe, or any IOChannel (e.g. a temporary file).
The command to run is specified as an argz
vector: a list of C strings with a null pointer to terminate the list, identical to the program's argv
list. The first element of argz
is the name of the command to execute, the subsequent elements are the arguments to it. All the information in argz
is always passed without modification or interpretation to the child process. By default the command name specifies the pathname of the file to be executed. Using Search changes this so that if the command does not include a path separator (slash (/) on unixen), the method duplicates the actions of shell in searching for an executable file in the directories listed in the $PATH shell environment variable.
Argz provides a way to build argz
lists dynamically. It also provides utilties for converting between argz
lists and strings to parse. One can force shell to parse of arguments by executing the platform equivalent of argz
= { "/bin/sh", "-c", command }. This is not portable and more importantly, ridden with all kinds of security risks if the contents of "command" are not strictly controlled to be only safe characters.
By default the subprocesses execute concurrently with the parent process. Use wait() to suspend the parent until the child exits and to find out its exit status. If the Synchronous is used when creating the subprocess, a wait() is executed immediately before the method returns.
To construct a subprocess chain, construct multiple SubProcess objects and chain them together. The First and Last flags must be used by the client to indicate which portion of the chain is being constructed. In addition, the Read flag may be used when constructing the last child to indicate that this will be the end of the chain and the parent expects to read from it. The Write flag may be used at the beginning of the chain to indicate that the parent expects to write to the chain (the caller must provide the Pipe for this). If there are more than one process in the chain, intermediate pipes are automatically created; when the next subprocess is created, it attaches itself to the other end of the pipe.
The different flags
combinations overlap. The purpose is to help clients express their needs in the most convenient terms. To avoid confusion in more complicated subprocess chain constructions it is simplest to think about each SubProcess as an individual redirection candidate. All subprocesses can have their input or output redirected from or to a pipe; for the first process in the chain input redirection from a pipe implies Write, for the last output redirection to a pipe implies Read, and for all but last output redirection means another subprocess will attach to the pipe. The implementation does not distinguish the pipe output redirections situations in any way, so different argument and call combinations can produce exactly the same result. The first and last processes may also have their input and output, respectively, redirected to a IOChannel, or inherit the parent's standard input or output. These are treated differently only in that the pipes are automatically closed in the parent once used in a child whereas bare IOChannel objects are not.
Attempting to simultanously both write to and read from a process causes deadlocks and therefore flags is not allowed to contain both Read and Write. Instead, if you read from the chain, redirect its input from a temporary file, or if you write to it, redirect its output to one; see TempFile::file() for a way to create temporary files. The deadlocks arise because pipes can buffer only a limited amount of data: once the buffer is full the caller will block until someone reads data off the other end. Indiscrete use of pipes to simultaneously read and write results in a deadlock where writes in both processes are blocked waiting on the other to read -- which neither is able to as they are blocked in their own write. It does not matter how many pipes are used, nor in fact whether subprocesses are involved: as long as the communication channel has limited buffering capacity and it blocks the writer when the buffer becomes full, the processes will deadlock sooner or later. The only workaround is to use non-blocking pipes and to explicitly buffer data at each end.
(FIXME: envz? close descriptors, clean up safe env?)
Definition at line 106 of file SubProcess.h.
Definition at line 116 of file SubProcess.h.
00116 { 00117 Read = 1, //< Make a read subprocess chain 00118 Write = 2, //< Make a write subprocess chain 00119 First = 4, //< First subprocess in a chain 00120 Last = 8, //< Last subprocess in a chain 00121 One = First | Last, //< Single-subprocess chain 00122 Synchronous = 16, //< Run synchronously 00123 Search = 32, //< Search path for command 00124 NoCloseInput = 64, //< Don't close input pipe in parent 00125 NoCloseOutput = 128 //< Don't close output pipe in parent 00126 // CleanEnv = 256 //< Clean up safe environment 00127 // CloseFds = 512 //< Close all "other" file descriptors 00128 };
lat::SubProcess::SubProcess | ( | void | ) |
lat::SubProcess::SubProcess | ( | const char ** | argz, | |
unsigned | flags = One | |||
) |
lat::SubProcess::SubProcess | ( | const char ** | argz, | |
unsigned | flags, | |||
Pipe * | pipe, | |||
IOChannel * | other = 0 | |||
) |
lat::SubProcess::SubProcess | ( | const char ** | argz, | |
unsigned | flags, | |||
SubProcess * | input, | |||
IOChannel * | output = 0 | |||
) |
lat::SubProcess::SubProcess | ( | const char ** | argz, | |
unsigned | flags, | |||
IOChannel * | input, | |||
IOChannel * | output = 0 | |||
) |
virtual lat::SubProcess::~SubProcess | ( | void | ) | [virtual] |
lat::SubProcess::SubProcess | ( | const SubProcess & | x | ) | [private] |
pid_t lat::SubProcess::dorun | ( | const char ** | argz, | |
unsigned | flags, | |||
IOChannel * | input, | |||
IOChannel * | output, | |||
IOChannel * | cleanup | |||
) | [private] |
SubProcess& lat::SubProcess::operator= | ( | const SubProcess & | x | ) | [private] |
virtual pid_t lat::SubProcess::pid | ( | void | ) | const [virtual] |
virtual pid_t lat::SubProcess::run | ( | const char ** | argz, | |
unsigned | flags, | |||
IOChannel * | input, | |||
IOChannel * | output = 0 | |||
) | [virtual] |
virtual pid_t lat::SubProcess::run | ( | const char ** | argz, | |
unsigned | flags, | |||
SubProcess * | input, | |||
IOChannel * | output = 0 | |||
) | [virtual] |
virtual pid_t lat::SubProcess::run | ( | const char ** | argz, | |
unsigned | flags, | |||
Pipe * | pipe, | |||
IOChannel * | other = 0 | |||
) | [virtual] |
virtual pid_t lat::SubProcess::run | ( | const char ** | argz, | |
unsigned | flags = One | |||
) | [virtual] |
Referenced by IgServerPool::createProcess().
pid_t lat::SubProcess::sysrun | ( | const char ** | argz, | |
unsigned | flags, | |||
IOChannel * | input, | |||
IOChannel * | output, | |||
IOChannel * | cleanup | |||
) | [private] |
IOChannel* lat::SubProcess::m_input [private] |
Definition at line 173 of file SubProcess.h.
IOChannel* lat::SubProcess::m_output [private] |
Definition at line 174 of file SubProcess.h.
Pipe* lat::SubProcess::m_pipe [private] |
Definition at line 175 of file SubProcess.h.
int lat::SubProcess::m_status [private] |
Definition at line 172 of file SubProcess.h.
pid_t lat::SubProcess::m_sub [private] |
Definition at line 180 of file SubProcess.h.