Current File : //usr/local/share/man/man3/POE::Wheel::Run.3pm |
.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
.\" nothing in troff, for use with C<>.
.tr \(*W-
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
. ds C`
. ds C'
'br\}
.\"
.\" Escape single quotes in literal strings from groff's Unicode transform.
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\"
.\" If the F register is >0, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.\"
.\" Avoid warning from groff about undefined register 'F'.
.de IX
..
.nr rF 0
.if \n(.g .if rF .nr rF 1
.if (\n(rF:(\n(.g==0)) \{\
. if \nF \{\
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. if !\nF==2 \{\
. nr % 0
. nr F 2
. \}
. \}
.\}
.rr rF
.\" ========================================================================
.\"
.IX Title "POE::Wheel::Run 3"
.TH POE::Wheel::Run 3 "2022-03-23" "perl v5.26.3" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.nh
.SH "NAME"
POE::Wheel::Run \- portably run blocking code and programs in subprocesses
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
.Vb 1
\& #!/usr/bin/perl
\&
\& use warnings;
\& use strict;
\&
\& use POE qw( Wheel::Run );
\&
\& POE::Session\->create(
\& inline_states => {
\& _start => \e&on_start,
\& got_child_stdout => \e&on_child_stdout,
\& got_child_stderr => \e&on_child_stderr,
\& got_child_close => \e&on_child_close,
\& got_child_signal => \e&on_child_signal,
\& }
\& );
\&
\& POE::Kernel\->run();
\& exit 0;
\&
\& sub on_start {
\& my $child = POE::Wheel::Run\->new(
\& Program => [ "/bin/ls", "\-1", "/" ],
\& StdoutEvent => "got_child_stdout",
\& StderrEvent => "got_child_stderr",
\& CloseEvent => "got_child_close",
\& );
\&
\& $_[KERNEL]\->sig_child($child\->PID, "got_child_signal");
\&
\& # Wheel events include the wheel\*(Aqs ID.
\& $_[HEAP]{children_by_wid}{$child\->ID} = $child;
\&
\& # Signal events include the process ID.
\& $_[HEAP]{children_by_pid}{$child\->PID} = $child;
\&
\& print(
\& "Child pid ", $child\->PID,
\& " started as wheel ", $child\->ID, ".\en"
\& );
\& }
\&
\& # Wheel event, including the wheel\*(Aqs ID.
\& sub on_child_stdout {
\& my ($stdout_line, $wheel_id) = @_[ARG0, ARG1];
\& my $child = $_[HEAP]{children_by_wid}{$wheel_id};
\& print "pid ", $child\->PID, " STDOUT: $stdout_line\en";
\& }
\&
\& # Wheel event, including the wheel\*(Aqs ID.
\& sub on_child_stderr {
\& my ($stderr_line, $wheel_id) = @_[ARG0, ARG1];
\& my $child = $_[HEAP]{children_by_wid}{$wheel_id};
\& print "pid ", $child\->PID, " STDERR: $stderr_line\en";
\& }
\&
\& # Wheel event, including the wheel\*(Aqs ID.
\& sub on_child_close {
\& my $wheel_id = $_[ARG0];
\& my $child = delete $_[HEAP]{children_by_wid}{$wheel_id};
\&
\& # May have been reaped by on_child_signal().
\& unless (defined $child) {
\& print "wid $wheel_id closed all pipes.\en";
\& return;
\& }
\&
\& print "pid ", $child\->PID, " closed all pipes.\en";
\& delete $_[HEAP]{children_by_pid}{$child\->PID};
\& }
\&
\& sub on_child_signal {
\& print "pid $_[ARG1] exited with status $_[ARG2].\en";
\& my $child = delete $_[HEAP]{children_by_pid}{$_[ARG1]};
\&
\& # May have been reaped by on_child_close().
\& return unless defined $child;
\&
\& delete $_[HEAP]{children_by_wid}{$child\->ID};
\& }
.Ve
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
POE::Wheel::Run executes a program or block of code in a subprocess,
created the usual way: using \fBfork()\fR. The parent process may exchange
information with the child over the child's \s-1STDIN, STDOUT\s0 and \s-1STDERR\s0
filehandles.
.PP
In the parent process, the POE::Wheel::Run object represents the child
process. It has methods such as \s-1\fBPID\s0()\fR and \fBkill()\fR to query and manage
the child process.
.PP
POE::Wheel::Run's \fBput()\fR method sends data to the child's \s-1STDIN.\s0 Child
output on \s-1STDOUT\s0 and \s-1STDERR\s0 may be dispatched as events within the
parent, if requested.
.PP
POE::Wheel::Run can also notify the parent when the child has closed
its output filehandles. Some programs remain active, but they close
their output filehandles to indicate they are done writing.
.PP
A more reliable way to detect child exit is to use POE::Kernel's
\&\fBsig_child()\fR method to wait for the wheel's process to be reaped. It
is in fact vital to use \fBsig_child()\fR in all circumstances since without
it, \s-1POE\s0 will not try to reap child processes.
.PP
Failing to use \fBsig_child()\fR has in the past led to wedged machines.
Long-running programs have leaked processes, eventually consuming all
available slots in the process table and requiring reboots.
.PP
Because process leaks are so severe, POE::Kernel will check for this
condition on exit and display a notice if it finds that processes are
leaking. Developers should heed these warnings.
.PP
POE::Wheel::Run communicates with the child process in a line-based
fashion by default. Programs may override this by specifying some
other POE::Filter object in \*(L"StdinFilter\*(R", \*(L"StdoutFilter\*(R",
\&\*(L"StdioFilter\*(R" and/or \*(L"StderrFilter\*(R".
.SH "PUBLIC METHODS"
.IX Header "PUBLIC METHODS"
.SS "Constructor"
.IX Subsection "Constructor"
POE::Wheel subclasses tend to perform a lot of setup so that they run
lighter and faster. POE::Wheel::Run's constructor is no exception.
.PP
\fInew\fR
.IX Subsection "new"
.PP
\&\fBnew()\fR creates and returns a new POE::Wheel::Run object. If it's
successful, the object will represent a child process with certain
specified qualities. It also provides an \s-1OO\-\s0 and event-based
interface for asynchronously interacting with the process.
.PP
Conduit
.IX Subsection "Conduit"
.PP
Conduit specifies the inter-process communications mechanism that will
be used to pass data between the parent and child process. Conduit
may be one of \*(L"pipe\*(R", \*(L"socketpair\*(R", \*(L"inet\*(R", \*(L"pty\*(R", or \*(L"pty-pipe\*(R".
POE::Wheel::Run will use the most appropriate Conduit for the run-time
(not the compile-time) operating system, but this varies from one \s-1OS\s0
to the next.
.PP
Internally, POE::Wheel::Run passes the Conduit type to
POE::Pipe::OneWay and POE::Pipe::TwoWay. These helper classes
were created to make \s-1IPC\s0 portable and reusable. They do not require
the rest of \s-1POE.\s0
.PP
Three Conduit types use pipes or pipelike inter-process communication:
\&\*(L"pipe\*(R", \*(L"socketpair\*(R" and \*(L"inet\*(R". They determine whether the internal
\&\s-1IPC\s0 uses \fBpipe()\fR, \fBsocketpair()\fR or Internet sockets. These Conduit
values are passed through to POE::Pipe::OneWay or
POE::Pipe::TwoWay internally.
.PP
The \*(L"pty\*(R" conduit type runs the child process under a pseudo-tty,
which is created by IO::Pty. Pseudo-ttys (ptys) convince child
processes that they are interacting with terminals rather than pipes.
This may be used to trick programs like ssh into believing it's secure
to prompt for a password, although passphraseless identities might be
better for that.
.PP
The \*(L"pty\*(R" conduit cannot separate \s-1STDERR\s0 from \s-1STDOUT,\s0 but the
\&\*(L"pty-pipe\*(R" mode can.
.PP
The \*(L"pty-pipe\*(R" conduit uses a pty for \s-1STDIN\s0 and \s-1STDOUT\s0 and a one-way
pipe for \s-1STDERR.\s0 The additional pipe keeps \s-1STDERR\s0 output separate
from \s-1STDOUT.\s0
.PP
The IO::Pty module is only loaded if \*(L"pty\*(R" or \*(L"pty-pipe\*(R" is used.
It's not a dependency until it's actually needed.
.PP
Winsize
.IX Subsection "Winsize"
.PP
Winsize sets the child process' terminal size. Its value should be an
arrayref with four elements. The first two elements must be the
number of lines and columns for the child's terminal window,
respectively. The second pair of elements describe the terminal's X
and Y dimensions in pixels. If the last pair is missing, they will be calculated
from the lines and columns using a 9x16 cell size.
.PP
.Vb 4
\& $_[HEAP]{child} = POE::Wheel::Run\->new(
\& # ... among other things ...
\& Winsize => [ 25, 80, 720, 400 ],
\& );
.Ve
.PP
Winsize is only valid for conduits that use pseudo-ttys: \*(L"pty\*(R" and
\&\*(L"pty-pipe\*(R". Other conduits don't simulate terminals, so they don't
have window sizes.
.PP
Winsize defaults to the parent process' window size, assuming the
parent process has a terminal to query.
.PP
CloseOnCall
.IX Subsection "CloseOnCall"
.PP
CloseOnCall, when true, turns on close-on-exec emulation for
subprocesses that don't actually call \fBexec()\fR. These would be
instances when the child is running a block of code rather than
executing an external program. For example:
.PP
.Vb 5
\& $_[HEAP]{child} = POE::Wheel::Run\->new(
\& # ... among other things ...
\& CloseOnCall => 1,
\& Program => \e&some_function,
\& );
.Ve
.PP
CloseOnCall is off (0) by default.
.PP
CloseOnCall works by closing all file descriptors greater than $^F in
the child process before calling the application's code. For more
details, please the discussion of $^F in perlvar.
.PP
StdioDriver
.IX Subsection "StdioDriver"
.PP
StdioDriver specifies a single POE::Driver object to be used for
both \s-1STDIN\s0 and \s-1STDOUT.\s0 It's equivalent to setting \*(L"StdinDriver\*(R" and
\&\*(L"StdoutDriver\*(R" to the same POE::Driver object.
.PP
POE::Wheel::Run will create and use a POE::Driver::SysRW driver of
one isn't specified. This is by far the most common use case, so it's
the default.
.PP
StdinDriver
.IX Subsection "StdinDriver"
.PP
\&\f(CW\*(C`StdinDriver\*(C'\fR sets the POE::Driver used to write to the child
process' \s-1STDIN IPC\s0 conduit. It is almost never needed. Omitting it
will allow POE::Wheel::Run to use an internally created
POE::Driver::SysRW object.
.PP
StdoutDriver
.IX Subsection "StdoutDriver"
.PP
\&\f(CW\*(C`StdoutDriver\*(C'\fR sets the POE::Driver object that will be used to
read from the child process' \s-1STDOUT\s0 conduit. It's almost never
needed. If omitted, POE::Wheel::Run will internally create and use
a POE::Driver::SysRW object.
.PP
StderrDriver
.IX Subsection "StderrDriver"
.PP
\&\f(CW\*(C`StderrDriver\*(C'\fR sets the driver that will be used to read from the
child process' \s-1STDERR\s0 conduit. As with \*(L"StdoutDriver\*(R", it's almost
always preferable to let POE::Wheel::Run instantiate its own driver.
.PP
CloseEvent
.IX Subsection "CloseEvent"
.PP
CloseEvent contains the name of an event that the wheel will emit when
the child process closes its last open output handle. This is a
consistent notification that the child is done sending output. Please
note that it does not signal when the child process has exited.
Programs should use \fBsig_child()\fR to detect that.
.PP
While it is impossible for ErrorEvent or StdoutEvent to happen after
CloseEvent, there is no such guarantee for \s-1CHLD,\s0 which may happen before
or after CloseEvent.
.PP
In addition to the usual \s-1POE\s0 parameters, each CloseEvent comes with
one of its own:
.PP
\&\f(CW\*(C`ARG0\*(C'\fR contains the wheel's unique \s-1ID.\s0 This can be used to keep
several child processes separate when they're managed by the same
session.
.PP
A sample close event handler:
.PP
.Vb 2
\& sub close_state {
\& my ($heap, $wheel_id) = @_[HEAP, ARG0];
\&
\& my $child = delete $heap\->{child}\->{$wheel_id};
\& print "Child ", $child\->PID, " has finished.\en";
\& }
.Ve
.PP
ErrorEvent
.IX Subsection "ErrorEvent"
.PP
ErrorEvent contains the name of an event to emit if something fails.
It is optional; if omitted, the wheel will not notify its session if
any errors occur. However, POE::Wheel::Run\->\fBnew()\fR will still throw an
exception if it fails.
.PP
\&\f(CW\*(C`ARG0\*(C'\fR contains the name of the operation that failed. It may be
\&'read', 'write', 'fork', 'exec' or the name of some other function or
task. The actual values aren't yet defined. They will probably not
correspond so neatly to Perl builtin function names.
.PP
\&\f(CW\*(C`ARG1\*(C'\fR and \f(CW\*(C`ARG2\*(C'\fR hold numeric and string values for \f(CW$!\fR,
respectively. \f(CW"$!"\fR will eq \f(CW""\fR for read error 0 (child process
closed the file handle).
.PP
\&\f(CW\*(C`ARG3\*(C'\fR contains the wheel's unique \s-1ID.\s0
.PP
\&\f(CW\*(C`ARG4\*(C'\fR contains the name of the child filehandle that has the error.
It may be \*(L"\s-1STDIN\*(R", \*(L"STDOUT\*(R",\s0 or \*(L"\s-1STDERR\*(R".\s0 The sense of \f(CW\*(C`ARG0\*(C'\fR will
be the opposite of what you might normally expect for these handles.
For example, POE::Wheel::Run will report a \*(L"read\*(R" error on \*(L"\s-1STDOUT\*(R"\s0
because it tried to read data from the child's \s-1STDOUT\s0 handle.
.PP
A sample error event handler:
.PP
.Vb 5
\& sub error_state {
\& my ($operation, $errnum, $errstr, $wheel_id) = @_[ARG0..ARG3];
\& $errstr = "remote end closed" if $operation eq "read" and !$errnum;
\& warn "Wheel $wheel_id generated $operation error $errnum: $errstr\en";
\& }
.Ve
.PP
Note that unless you deactivate the signal pipe, you might also see \f(CW\*(C`EIO\*(C'\fR
(5) error during read operations.
.PP
StdinEvent
.IX Subsection "StdinEvent"
.PP
StdinEvent contains the name of an event that Wheel::Run emits
whenever everything queued by its \fBput()\fR method has been flushed to the
child's \s-1STDIN\s0 handle. It is the equivalent to POE::Wheel::ReadWrite's
FlushedEvent.
.PP
StdinEvent comes with only one additional parameter: \f(CW\*(C`ARG0\*(C'\fR contains
the unique \s-1ID\s0 for the wheel that sent the event.
.PP
StdoutEvent
.IX Subsection "StdoutEvent"
.PP
StdoutEvent contains the name of an event that Wheel::Run emits
whenever the child process writes something to its \s-1STDOUT\s0 filehandle.
In other words, whatever the child prints to \s-1STDOUT,\s0 the parent
receives a StdoutEvent\-\-\-provided that the child prints something
compatible with the parent's StdoutFilter.
.PP
StdoutEvent comes with two parameters. \f(CW\*(C`ARG0\*(C'\fR contains the
information that the child wrote to \s-1STDOUT.\s0 \f(CW\*(C`ARG1\*(C'\fR holds the unique
\&\s-1ID\s0 of the wheel that read the output.
.PP
.Vb 4
\& sub stdout_state {
\& my ($heap, $input, $wheel_id) = @_[HEAP, ARG0, ARG1];
\& print "Child process in wheel $wheel_id wrote to STDOUT: $input\en";
\& }
.Ve
.PP
StderrEvent
.IX Subsection "StderrEvent"
.PP
StderrEvent behaves exactly as StdoutEvent, except for data the child
process writes to its \s-1STDERR\s0 filehandle.
.PP
StderrEvent comes with two parameters. \f(CW\*(C`ARG0\*(C'\fR contains the
information that the child wrote to \s-1STDERR.\s0 \f(CW\*(C`ARG1\*(C'\fR holds the unique
\&\s-1ID\s0 of the wheel that read the output.
.PP
.Vb 4
\& sub stderr_state {
\& my ($heap, $input, $wheel_id) = @_[HEAP, ARG0, ARG1];
\& print "Child process in wheel $wheel_id wrote to STDERR: $input\en";
\& }
.Ve
.PP
RedirectStdout
.IX Subsection "RedirectStdout"
.PP
This is a filehandle or filename to which standard output will be redirected.
It is an error to use this option together with StdoutEvent. This is useful
in case your program needs to have standard I/O, but do not actually care for
its contents to be visible to the parent.
.PP
RedirectStderr
.IX Subsection "RedirectStderr"
.PP
Just like RedirectStdout, but with standard error. It is an error to use this
together with StderrEvent
.PP
RedirectStdin
.IX Subsection "RedirectStdin"
.PP
This is a filehandle or filename which the child process will use as its
standard input. It is an error to use this option with StdinEvent
.PP
RedirectOutput
.IX Subsection "RedirectOutput"
.PP
This will redirect stderr and stdout to the same filehandle. This is equivalent
to do doing something like
.PP
.Vb 1
\& $ something > /path/to/output 2>&1
.Ve
.PP
in bourne shell.
.PP
NoStdin
.IX Subsection "NoStdin"
.PP
While output filehandles will be closed if there are no events to be received on
them, stdin is open by default \- because lack of an event handler does not
necessarily mean there is no desired input stream. This option explicitly
disables the creation of an \s-1IPC\s0 stdin conduit.
.PP
StdioFilter
.IX Subsection "StdioFilter"
.PP
StdioFilter, if used, must contain an instance of a POE::Filter
subclass. This filter describes how the parent will format \fBput()\fR data
for the child's \s-1STDIN,\s0 and how the parent will parse the child's
\&\s-1STDOUT.\s0
.PP
If \s-1STDERR\s0 will also be parsed, then a separate StderrFilter will also
be needed.
.PP
StdioFilter defaults to a POE::Filter::Line instance, but only if both
StdinFilter and StdoutFilter are not specified. If either StdinFilter
or StdoutFilter is used, then StdioFilter is illegal.
.PP
StdinFilter
.IX Subsection "StdinFilter"
.PP
StdinFilter may be used to specify a particular \s-1STDIN\s0 serializer that
is different from the \s-1STDOUT\s0 parser. If specified, it conflicts with
StdioFilter. StdinFilter's value, if specified, must be an instance
of a POE::Filter subclass.
.PP
Without a StdinEvent, StdinFilter is illegal.
.PP
StdoutFilter
.IX Subsection "StdoutFilter"
.PP
StdoutFilter may be used to specify a particular \s-1STDOUT\s0 parser that is
different from the \s-1STDIN\s0 serializer. If specified, it conflicts with
StdioFilter. StdoutFilter's value, if specified, must be an instance
of a POE::Filter subclass.
.PP
Without a StdoutEvent, StdoutFilter is illegal.
.PP
StderrFilter
.IX Subsection "StderrFilter"
.PP
StderrFilter may be used to specify a filter for a child process'
\&\s-1STDERR\s0 output. If omitted, POE::Wheel::Run will create and use its
own POE::Filter::Line instance, but only if a StderrEvent is
specified.
.PP
Without a StderrEvent, StderrFilter is illegal.
.PP
Group
.IX Subsection "Group"
.PP
Group contains a numeric group \s-1ID\s0 that the child process should run
within. By default, the child process will run in the same group as
the parent.
.PP
Group is not fully portable. It may not work on systems that have no
concept of user groups. Also, the parent process may need to run with
elevated privileges for the child to be able to change groups.
.PP
User
.IX Subsection "User"
.PP
User contains a numeric user \s-1ID\s0 that should own the child process. By
default, the child process will run as the same user as the parent.
.PP
User is not fully portable. It may not work on systems that have no
concept of users. Also, the parent process may need to run with
elevated privileges for the child to be able to change users.
.PP
NoSetSid
.IX Subsection "NoSetSid"
.PP
When true, NoSetSid disables \fBsetsid()\fR in the child process. By
default, the child process calls \fBsetsid()\fR is called so that it may
execute in a separate \s-1UNIX\s0 session.
.PP
This option is deprecated. As IO::Pty uses \f(CW\*(C`setsid()\*(C'\fR this module
has no control on whether it is invoked or not.
.PP
NoSetPgrp
.IX Subsection "NoSetPgrp"
.PP
When true, NoSetPgrp disables \fBsetprgp()\fR in the child process. By
default, the child process calls \fBsetpgrp()\fR to change its process
group, if the \s-1OS\s0 supports that.
.PP
\&\fBsetsid()\fR is used instead of \fBsetpgrp()\fR if Conduit is pty or pty-pipe.
See \*(L"NoSetSid\*(R".
.PP
Priority
.IX Subsection "Priority"
.PP
Priority adjusts the child process' niceness or priority level,
depending on which (if any) the underlying \s-1OS\s0 supports. Priority
contains a numeric offset which will be added to the parent's priority
to determine the child's.
.PP
The priority offset may be negative, which in \s-1UNIX\s0 represents a higher
priority. However \s-1UNIX\s0 requires elevated privileges to increase a
process' priority.
.PP
Program
.IX Subsection "Program"
.PP
Program specifies the program to \fBexec()\fR or the block of code to run in
the child process. Program's type is significant.
.PP
If Program holds a scalar, its value will be executed as
exec($program). Shell metacharacters are significant, per
exec(\s-1SCALAR\s0) semantics.
.PP
If Program holds an array reference, it will executed as
exec(@$program). As per exec(\s-1ARRAY\s0), shell metacharacters will not be
significant.
.PP
If Program holds a code reference, that code will be called in the
child process. This mode allows POE::Wheel::Run to execute
long-running internal code asynchronously, while the usual modes
execute external programs. The child process will exit after that
code is finished, in such a way as to avoid \s-1DESTROY\s0 and \s-1END\s0 block
execution. See \*(L"Coderef Execution Side Effects\*(R" for more details.
.PP
perlfunc has more information about \fBexec()\fR and the different ways
to call it.
.PP
Please avoid calling \fBexit()\fR explicitly when executing a subroutine.
The child process inherits all objects from the parent, including ones
that may perform side effects. POE::Wheel::Run takes special care to
avoid object destructors and \s-1END\s0 blocks in the child process, but
calling \fBexit()\fR will trigger them.
.PP
ProgramArgs
.IX Subsection "ProgramArgs"
.PP
If specified, ProgramArgs should refer to a list of parameters for the
program being run.
.PP
.Vb 2
\& my @parameters = qw(foo bar baz); # will be passed to Program
\& ProgramArgs => \e@parameters;
.Ve
.SS "event \s-1EVENT_TYPE\s0 => \s-1EVENT_NAME, ...\s0"
.IX Subsection "event EVENT_TYPE => EVENT_NAME, ..."
\&\fBevent()\fR allows programs to change the events that Wheel::Run emits
when certain activities occurs. \s-1EVENT_TYPE\s0 may be one of the event
parameters described in POE::Wheel::Run's constructor.
.PP
This example changes the events that \f(CW$wheel\fR emits for \s-1STDIN\s0 flushing
and \s-1STDOUT\s0 activity:
.PP
.Vb 4
\& $wheel\->event(
\& StdinEvent => \*(Aqnew\-stdin\-event\*(Aq,
\& StdoutEvent => \*(Aqnew\-stdout\-event\*(Aq,
\& );
.Ve
.PP
Undefined EVENT_NAMEs disable events.
.SS "put \s-1RECORDS\s0"
.IX Subsection "put RECORDS"
\&\fBput()\fR queues up a list of \s-1RECORDS\s0 that will be sent to the child
process' \s-1STDIN\s0 filehandle. These records will first be serialized
according to the wheel's StdinFilter. The serialized \s-1RECORDS\s0 will be
flushed asynchronously once the current event handler returns.
.SS "get_stdin_filter"
.IX Subsection "get_stdin_filter"
\&\fBget_stind_filter()\fR returns the POE::Filter object currently being used
to serialize \fBput()\fR records for the child's \s-1STDIN\s0 filehandle. The
return object may be used according to its own interface.
.SS "get_stdout_filter"
.IX Subsection "get_stdout_filter"
\&\fBget_stdout_filter()\fR returns the POE::Filter object currently being
used to parse what the child process writes to \s-1STDOUT.\s0
.SS "get_stderr_filter"
.IX Subsection "get_stderr_filter"
\&\fBget_stderr_filter()\fR returns the POE::Filter object currently being
used to parse what the child process writes to \s-1STDERR.\s0
.SS "set_stdio_filter \s-1FILTER_OBJECT\s0"
.IX Subsection "set_stdio_filter FILTER_OBJECT"
Set StdinFilter and StdoutFilter to the same new \s-1FILTER_OBJECT.\s0
Unparsed \s-1STDOUT\s0 data will be parsed later by the new \s-1FILTER_OBJECT.\s0
However, data already \fBput()\fR will remain serialized by the old filter.
.SS "set_stdin_filter \s-1FILTER_OBJECT\s0"
.IX Subsection "set_stdin_filter FILTER_OBJECT"
Set StdinFilter to a new \s-1FILTER_OBJECT.\s0 Data already \fBput()\fR will
remain serialized by the old filter.
.SS "set_stdout_filter \s-1FILTER_OBJECT\s0"
.IX Subsection "set_stdout_filter FILTER_OBJECT"
Set StdoutFilter to a new \s-1FILTER_OBJECT.\s0 Unparsed \s-1STDOUT\s0 data will be
parsed later by the new \s-1FILTER_OBJECT.\s0
.SS "set_stderr_filter \s-1FILTER_OBJECT\s0"
.IX Subsection "set_stderr_filter FILTER_OBJECT"
Set StderrFilter to a new \s-1FILTER_OBJECT.\s0 Unparsed \s-1STDERR\s0 data will be
parsed later by the new \s-1FILTER_OBJECT.\s0
.SS "pause_stdout"
.IX Subsection "pause_stdout"
Pause reading of \s-1STDOUT\s0 from the child. The child process may block
if the \s-1STDOUT IPC\s0 conduit fills up. Reading may be resumed with
\&\fBresume_stdout()\fR.
.SS "pause_stderr"
.IX Subsection "pause_stderr"
Pause reading of \s-1STDERR\s0 from the child. The child process may block
if the \s-1STDERR IPC\s0 conduit fills up. Reading may be resumed with
\&\fBresume_stderr()\fR.
.SS "resume_stdout"
.IX Subsection "resume_stdout"
Resume reading from the child's \s-1STDOUT\s0 filehandle. This is only
meaningful if \fBpause_stdout()\fR has been called and remains in effect.
.SS "resume_stderr"
.IX Subsection "resume_stderr"
Resume reading from the child's \s-1STDERR\s0 filehandle. This is only
meaningful if \fBpause_stderr()\fR has been called and remains in effect.
.SS "shutdown_stdin"
.IX Subsection "shutdown_stdin"
\&\fBshutdown_stdin()\fR closes the child process' \s-1STDIN\s0 and stops the wheel
from reporting StdinEvent. It is extremely useful for running
utilities that expect to receive \s-1EOF\s0 on \s-1STDIN\s0 before they respond.
.SS "\s-1ID\s0"
.IX Subsection "ID"
\&\s-1\fBID\s0()\fR returns the wheel's unique \s-1ID.\s0 Every event generated by a
POE::Wheel::Run object includes a wheel \s-1ID\s0 so that it can be matched
to the wheel that emitted it. This lets a single session manage
several wheels without becoming confused about which one generated
what event.
.PP
\&\s-1\fBID\s0()\fR is not the same as \s-1\fBPID\s0()\fR.
.SS "\s-1PID\s0"
.IX Subsection "PID"
\&\s-1\fBPID\s0()\fR returns the process \s-1ID\s0 for the child represented by the
POE::Wheel::Run object. It's often used as a parameter to
\&\fBsig_child()\fR.
.PP
\&\s-1\fBPID\s0()\fR is not the same as \s-1\fBID\s0()\fR.
.SS "kill \s-1SIGNAL\s0"
.IX Subsection "kill SIGNAL"
POE::Wheel::Run's \fBkill()\fR method sends a \s-1SIGNAL\s0 to the child process
the object represents. \fBkill()\fR is often used to force a reluctant
program to terminate. \s-1SIGNAL\s0 is one of the operating signal names
present in \f(CW%SIG\fR.
.PP
\&\fBkill()\fR returns the number of processes successfully signaled: 1 on
success, or 0 on failure, since the POE::Wheel::Run object only
affects at most a single process.
.PP
\&\fBkill()\fR sends \s-1SIGTERM\s0 if \s-1SIGNAL\s0 is undef or omitted.
.SS "get_driver_out_messages"
.IX Subsection "get_driver_out_messages"
\&\fBget_driver_out_messages()\fR returns the number of \fBput()\fR records
remaining in whole or in part in POE::Wheel::Run's POE::Driver output
queue. It is often used to tell whether the wheel has more input for
the child process.
.PP
In most cases, StdinEvent may be used to trigger activity when all
data has been sent to the child process.
.SS "get_driver_out_octets"
.IX Subsection "get_driver_out_octets"
\&\fBget_driver_out_octets()\fR returns the number of serialized octets
remaining in POE::Wheel::Run's POE::Driver output queue. It is often
used to tell whether the wheel has more input for the child process.
.SH "TIPS AND TRICKS"
.IX Header "TIPS AND TRICKS"
.SS "MSWin32 Support"
.IX Subsection "MSWin32 Support"
In the past POE::Wheel::Run did not support MSWin32 and users had to
use custom work-arounds. Then Chris Williams ( \s-1BINGOS\s0 ) arrived and
saved the day with his POE::Wheel::Run::Win32 module. After some
testing, it was decided to merge the win32 code into POE::Wheel::Run.
Everyone was happy!
.PP
However, after some investigation Apocalypse ( \s-1APOCAL\s0 ) found out that
in some situations it still didn't behave properly. The root cause was
that the win32 code path in POE::Wheel::Run didn't exit cleanly. This
means \s-1DESTROY\s0 and \s-1END\s0 blocks got executed! After talking with more
people, the solution was not pretty.
.PP
The problem is that there is no equivalent of \fBPOSIX::_exit()\fR for MSWin32.
Hopefully, in a future version of Perl this can be fixed! In the meantime,
POE::Wheel::Run will use \fBCORE::kill()\fR to terminate the child. However,
this comes with a caveat: you will leak around 1KB per exec. The code
has been improved so the chance of this happening has been reduced.
.PP
As of now the most reliable way to trigger this is to exec an invalid
binary. The definition of \*(L"invalid binary\*(R" depends on different things,
but what it means is that Win32::Job\->\fBspawn()\fR failed to run. This will
force POE::Wheel::Run to use the workaround to exit the child. If this
happens, a very big warning will be printed to the \s-1STDERR\s0 of the child
and the parent process will receive it.
.PP
If you are a Perl MSWin32 hacker, \s-1PLEASE\s0 help us with this situation! Go
read rt.cpan.org bug #56417 and talk with us/p5p to see where you can
contribute.
.PP
Thanks again for your patience as we continue to improve POE::Wheel::Run
on MSWin32!
.PP
\fI\f(BIkill()\fI and ClosedEvent on Windows\fR
.IX Subsection "kill() and ClosedEvent on Windows"
.PP
Windows will often fail to report \s-1EOF\s0 on pipes when subprocesses are
killed. The work-around is to catch the signal in the subprocess, and
exit normally:
.PP
.Vb 7
\& my $child = POE::Wheel::Run\->new(
\& Program => sub {
\& $SIG{INT} = sub { exit };
\& ...;
\& },
\& ...,
\& );
.Ve
.PP
Be sure to \fBkill()\fR the subprocess using the same signal that it catches
and exits upon. Remember, not all signals can be caught by user code.
.PP
.Vb 1
\& $child\->kill("INT");
.Ve
.SS "Execution Environment"
.IX Subsection "Execution Environment"
It's common to scrub a child process' environment, so that only
required, secure values exist. This amounts to clearing the contents
of \f(CW%ENV\fR and repopulating it.
.PP
Environment scrubbing is easy when the child process is running a
subroutine, but it's not so easy\-\-\-or at least not as intuitive\-\-\-when
executing external programs.
.PP
The way we do it is to run a small subroutine in the child process
that performs the \fBexec()\fR call for us.
.PP
.Vb 1
\& Program => \e&exec_with_scrubbed_env,
\&
\& sub exec_with_scrubbed_env {
\& delete @ENV{keys @ENV};
\& $ENV{PATH} = "/bin";
\& exec(@program_and_args);
\& }
.Ve
.PP
That deletes everything from the environment and sets a simple, secure
\&\s-1PATH\s0 before executing a program.
.SS "Coderef Execution Side Effects"
.IX Subsection "Coderef Execution Side Effects"
The child process is created by \fBfork()\fR, which duplicates the parent
process including a copy of POE::Kernel, all running Session
instances, events in the queue, watchers, open filehandles, and so on.
.PP
When executing an external program, the \s-1UNIX\s0 \fBexec()\fR call immediately
replaces the copy of the parent with a completely new program.
.PP
When executing internal coderefs, however, we must preserve the code
and any memory it might reference. This leads to some potential side
effects.
.PP
\fI\s-1DESTROY\s0 and \s-1END\s0 Blocks Run Twice\fR
.IX Subsection "DESTROY and END Blocks Run Twice"
.PP
Objects that were created in the parent process are copied into the
child. When the child exits normally, any \s-1DESTROY\s0 and \s-1END\s0 blocks are
executed there. Later, when the parent exits, they may run again.
.PP
POE::Wheel::Run takes steps to avoid running \s-1DESTROY\s0 and \s-1END\s0 blocks in
the child process. It uses \fBPOSIX::_exit()\fR to bypass them. If that
fails, it may even \fBkill()\fR itself.
.PP
If an application needs to exit explicitly, for example to return an
error code to the parent process, then please use \fBPOSIX::_exit()\fR
rather than Perl's core \fBexit()\fR.
.PP
\fIPOE::Kernel's \f(BIrun()\fI method was never called\fR
.IX Subsection "POE::Kernel's run() method was never called"
.PP
This warning is displayed from POE::Kernel's \s-1DESTROY\s0 method. It's a
side effect of calling \fBexit()\fR in a child process that was started
before \f(CW\*(C`POE::Kernel\->run()\*(C'\fR could be called. The child process
receives a copy of POE::Kernel where \fBrun()\fR wasn't called, even if it
was called later in the parent process.
.PP
The most direct solution is to call \fBPOSIX::_exit()\fR rather than \fBexit()\fR.
This will bypass POE::Kernel's \s-1DESTROY,\s0 and the message it emits.
.PP
\fIRunning POE::Kernel in the Child\fR
.IX Subsection "Running POE::Kernel in the Child"
.PP
Calling \f(CW\*(C`POE::Kernel\->run()\*(C'\fR in the child process effectively
resumes the copy of the parent process. This is rarely (if ever)
desired.
.PP
More commonly, an application wants to run an entirely new POE::Kernel
instance in the child process. This is supported by first \fBstop()\fRping
the copied instance, starting one or more new sessions, and calling
\&\fBrun()\fR again. For example:
.PP
.Vb 3
\& Program => sub {
\& # Wipe the existing POE::Kernel clean.
\& $poe_kernel\->stop();
\&
\& # Start a new session, or more.
\& POE::Session\->create(
\& ...
\& );
\&
\& # Run the new sessions.
\& POE::Kernel\->run();
\& }
.Ve
.PP
Strange things are bound to happen if the program does not call
\&\*(L"stop\*(R" in POE::Kernel before \*(L"run\*(R" in POE::Kernel. However this is
vaguely supported in case it's the right thing to do at the time.
.SH "SEE ALSO"
.IX Header "SEE ALSO"
POE::Wheel describes wheels in general.
.PP
The \s-1SEE ALSO\s0 section in \s-1POE\s0 contains a table of contents covering
the entire \s-1POE\s0 distribution.
.SH "CAVEATS & TODOS"
.IX Header "CAVEATS & TODOS"
POE::Wheel::Run's constructor should emit proper events when it fails.
Instead, it just dies, carps or croaks. This isn't necessarily bad; a
program can trap the death in \fBnew()\fR and move on.
.PP
Priority is a delta, not an absolute niceness value.
.PP
It might be nice to specify User by name rather than just \s-1UID.\s0
.PP
It might be nice to specify Group by name rather than just \s-1GID.\s0
.PP
POE::Pipe::OneWay and Two::Way don't require the rest of \s-1POE.\s0 They
should be spun off into a separate distribution for everyone to enjoy.
.PP
If StdinFilter and StdoutFilter seem backwards, remember that it's the
filters for the child process. StdinFilter is the one that dictates
what the child receives on \s-1STDIN.\s0 StdoutFilter tells the parent how
to parse the child's \s-1STDOUT.\s0
.SH "AUTHORS & COPYRIGHTS"
.IX Header "AUTHORS & COPYRIGHTS"
Please see \s-1POE\s0 for more information about authors and contributors.