1POE::Wheel::Run(3) User Contributed Perl Documentation POE::Wheel::Run(3)
2
3
4
6 POE::Wheel::Run - portably run blocking code and programs in
7 subprocesses
8
10 #!/usr/bin/perl
11
12 use warnings;
13 use strict;
14
15 use POE qw( Wheel::Run );
16
17 POE::Session->create(
18 inline_states => {
19 _start => \&on_start,
20 got_child_stdout => \&on_child_stdout,
21 got_child_stderr => \&on_child_stderr,
22 got_child_close => \&on_child_close,
23 got_child_signal => \&on_child_signal,
24 }
25 );
26
27 POE::Kernel->run();
28 exit 0;
29
30 sub on_start {
31 my $child = POE::Wheel::Run->new(
32 Program => [ "/bin/ls", "-1", "/" ],
33 StdoutEvent => "got_child_stdout",
34 StderrEvent => "got_child_stderr",
35 CloseEvent => "got_child_close",
36 );
37
38 $_[KERNEL]->sig_child($child->PID, "got_child_signal");
39
40 # Wheel events include the wheel's ID.
41 $_[HEAP]{children_by_wid}{$child->ID} = $child;
42
43 # Signal events include the process ID.
44 $_[HEAP]{children_by_pid}{$child->PID} = $child;
45
46 print(
47 "Child pid ", $child->PID,
48 " started as wheel ", $child->ID, ".\n"
49 );
50 }
51
52 # Wheel event, including the wheel's ID.
53 sub on_child_stdout {
54 my ($stdout_line, $wheel_id) = @_[ARG0, ARG1];
55 my $child = $_[HEAP]{children_by_wid}{$wheel_id};
56 print "pid ", $child->PID, " STDOUT: $stdout_line\n";
57 }
58
59 # Wheel event, including the wheel's ID.
60 sub on_child_stderr {
61 my ($stderr_line, $wheel_id) = @_[ARG0, ARG1];
62 my $child = $_[HEAP]{children_by_wid}{$wheel_id};
63 print "pid ", $child->PID, " STDERR: $stderr_line\n";
64 }
65
66 # Wheel event, including the wheel's ID.
67 sub on_child_close {
68 my $wheel_id = $_[ARG0];
69 my $child = delete $_[HEAP]{children_by_wid}{$wheel_id};
70
71 # May have been reaped by on_child_signal().
72 unless (defined $child) {
73 print "wid $wheel_id closed all pipes.\n";
74 return;
75 }
76
77 print "pid ", $child->PID, " closed all pipes.\n";
78 delete $_[HEAP]{children_by_pid}{$child->PID};
79 }
80
81 sub on_child_signal {
82 print "pid $_[ARG1] exited with status $_[ARG2].\n";
83 my $child = delete $_[HEAP]{children_by_pid}{$_[ARG1]};
84
85 # May have been reaped by on_child_close().
86 return unless defined $child;
87
88 delete $_[HEAP]{children_by_wid}{$child->ID};
89 }
90
92 POE::Wheel::Run executes a program or block of code in a subprocess,
93 created the usual way: using fork(). The parent process may exchange
94 information with the child over the child's STDIN, STDOUT and STDERR
95 filehandles.
96
97 In the parent process, the POE::Wheel::Run object represents the child
98 process. It has methods such as PID() and kill() to query and manage
99 the child process.
100
101 POE::Wheel::Run's put() method sends data to the child's STDIN. Child
102 output on STDOUT and STDERR may be dispatched as events within the
103 parent, if requested.
104
105 POE::Wheel::Run can also notify the parent when the child has closed
106 its output filehandles. Some programs remain active, but they close
107 their output filehandles to indicate they are done writing.
108
109 A more reliable way to detect child exit is to use POE::Kernel's
110 sig_child() method to wait for the wheel's process to be reaped. It is
111 in fact vital to use sig_child() in all circumstances since without it,
112 POE will not try to reap child processes.
113
114 Failing to use sig_child() has in the past led to wedged machines.
115 Long-running programs have leaked processes, eventually consuming all
116 available slots in the process table and requiring reboots.
117
118 Because process leaks are so severe, POE::Kernel will check for this
119 condition on exit and display a notice if it finds that processes are
120 leaking. Developers should heed these warnings.
121
122 POE::Wheel::Run communicates with the child process in a line-based
123 fashion by default. Programs may override this by specifying some
124 other POE::Filter object in "StdinFilter", "StdoutFilter",
125 "StdioFilter" and/or "StderrFilter".
126
128 Constructor
129 POE::Wheel subclasses tend to perform a lot of setup so that they run
130 lighter and faster. POE::Wheel::Run's constructor is no exception.
131
132 new
133
134 new() creates and returns a new POE::Wheel::Run object. If it's
135 successful, the object will represent a child process with certain
136 specified qualities. It also provides an OO- and event-based interface
137 for asynchronously interacting with the process.
138
139 Conduit
140
141 Conduit specifies the inter-process communications mechanism that will
142 be used to pass data between the parent and child process. Conduit may
143 be one of "pipe", "socketpair", "inet", "pty", or "pty-pipe".
144 POE::Wheel::Run will use the most appropriate Conduit for the run-time
145 (not the compile-time) operating system, but this varies from one OS to
146 the next.
147
148 Internally, POE::Wheel::Run passes the Conduit type to
149 POE::Pipe::OneWay and POE::Pipe::TwoWay. These helper classes were
150 created to make IPC portable and reusable. They do not require the
151 rest of POE.
152
153 Three Conduit types use pipes or pipelike inter-process communication:
154 "pipe", "socketpair" and "inet". They determine whether the internal
155 IPC uses pipe(), socketpair() or Internet sockets. These Conduit
156 values are passed through to POE::Pipe::OneWay or POE::Pipe::TwoWay
157 internally.
158
159 The "pty" conduit type runs the child process under a pseudo-tty, which
160 is created by IO::Pty. Pseudo-ttys (ptys) convince child processes
161 that they are interacting with terminals rather than pipes. This may
162 be used to trick programs like ssh into believing it's secure to prompt
163 for a password, although passphraseless identities might be better for
164 that.
165
166 The "pty" conduit cannot separate STDERR from STDOUT, but the "pty-
167 pipe" mode can.
168
169 The "pty-pipe" conduit uses a pty for STDIN and STDOUT and a one-way
170 pipe for STDERR. The additional pipe keeps STDERR output separate from
171 STDOUT.
172
173 The IO::Pty module is only loaded if "pty" or "pty-pipe" is used. It's
174 not a dependency until it's actually needed.
175
176 TODO - Example.
177
178 Winsize
179
180 Winsize sets the child process' terminal size. Its value should be an
181 arrayref with two or four elements. The first two elements must be the
182 number of lines and columns for the child's terminal window,
183 respectively. The optional pair of elements describe the terminal's X
184 and Y dimensions in pixels:
185
186 $_[HEAP]{child} = POE::Wheel::Run->new(
187 # ... among other things ...
188 Winsize => [ 25, 80, 1024, 768 ],
189 );
190
191 Winsize is only valid for conduits that use pseudo-ttys: "pty" and
192 "pty-pipe". Other conduits don't simulate terminals, so they don't
193 have window sizes.
194
195 Winsize defaults to the parent process' window size, assuming the
196 parent process has a terminal to query.
197
198 CloseOnCall
199
200 CloseOnCall, when true, turns on close-on-exec emulation for
201 subprocesses that don't actually call exec(). These would be instances
202 when the child is running a block of code rather than executing an
203 external program. For example:
204
205 $_[HEAP]{child} = POE::Wheel::Run->new(
206 # ... among other things ...
207 CloseOnCall => 1,
208 Program => \&some_function,
209 );
210
211 CloseOnCall is off (0) by default.
212
213 CloseOnCall works by closing all file descriptors greater than $^F in
214 the child process before calling the application's code. For more
215 details, please the discussion of $^F in perlvar.
216
217 StdioDriver
218
219 StdioDriver specifies a single POE::Driver object to be used for both
220 STDIN and STDOUT. It's equivalent to setting "StdinDriver" and
221 "StdoutDriver" to the same POE::Driver object.
222
223 POE::Wheel::Run will create and use a POE::Driver::SysRW driver of one
224 isn't specified. This is by far the most common use case, so it's the
225 default.
226
227 StdinDriver
228
229 "StdinDriver" sets the POE::Driver used to write to the child process'
230 STDIN IPC conduit. It is almost never needed. Omitting it will allow
231 POE::Wheel::Run to use an internally created POE::Driver::SysRW object.
232
233 StdoutDriver
234
235 "StdoutDriver" sets the POE::Driver object that will be used to read
236 from the child process' STDOUT conduit. It's almost never needed. If
237 omitted, POE::Wheel::Run will internally create and use a
238 POE::Driver::SysRW object.
239
240 StderrDriver
241
242 "StderrDriver" sets the driver that will be used to read from the child
243 process' STDERR conduit. As with "StdoutDriver", it's almost always
244 preferable to let POE::Wheel::Run instantiate its own driver.
245
246 CloseEvent
247
248 CloseEvent contains the name of an event that the wheel will emit when
249 the child process closes its last open output handle. This is a
250 consistent notification that the child is done sending output. Please
251 note that it does not signal when the child process has exited.
252 Programs should use sig_child() to detect that.
253
254 While it is impossible for ErrorEvent or StdoutEvent to happen after
255 CloseEvent, there is no such guarantee for CHLD, which may happen
256 before or after CloseEvent.
257
258 In addition to the usual POE parameters, each CloseEvent comes with one
259 of its own:
260
261 "ARG0" contains the wheel's unique ID. This can be used to keep
262 several child processes separate when they're managed by the same
263 session.
264
265 A sample close event handler:
266
267 sub close_state {
268 my ($heap, $wheel_id) = @_[HEAP, ARG0];
269
270 my $child = delete $heap->{child}->{$wheel_id};
271 print "Child ", $child->PID, " has finished.\n";
272 }
273
274 ErrorEvent
275
276 ErrorEvent contains the name of an event to emit if something fails.
277 It is optional; if omitted, the wheel will not notify its session if
278 any errors occur. However, POE::Wheel::Run->new() will still throw an
279 exception if it fails.
280
281 "ARG0" contains the name of the operation that failed. It may be
282 'read', 'write', 'fork', 'exec' or the name of some other function or
283 task. The actual values aren't yet defined. They will probably not
284 correspond so neatly to Perl builtin function names.
285
286 "ARG1" and "ARG2" hold numeric and string values for $!, respectively.
287 "$!" will eq "" for read error 0 (child process closed the file
288 handle).
289
290 "ARG3" contains the wheel's unique ID.
291
292 "ARG4" contains the name of the child filehandle that has the error.
293 It may be "STDIN", "STDOUT", or "STDERR". The sense of "ARG0" will be
294 the opposite of what you might normally expect for these handles. For
295 example, POE::Wheel::Run will report a "read" error on "STDOUT" because
296 it tried to read data from the child's STDOUT handle.
297
298 A sample error event handler:
299
300 sub error_state {
301 my ($operation, $errnum, $errstr, $wheel_id) = @_[ARG0..ARG3];
302 $errstr = "remote end closed" if $operation eq "read" and !$errnum;
303 warn "Wheel $wheel_id generated $operation error $errnum: $errstr\n";
304 }
305
306 Note that unless you deactivate the signal pipe, you might also see
307 "EIO" (5) error during read operations.
308
309 StdinEvent
310
311 StdinEvent contains the name of an event that Wheel::Run emits whenever
312 everything queued by its put() method has been flushed to the child's
313 STDIN handle. It is the equivalent to POE::Wheel::ReadWrite's
314 FlushedEvent.
315
316 StdinEvent comes with only one additional parameter: "ARG0" contains
317 the unique ID for the wheel that sent the event.
318
319 StdoutEvent
320
321 StdoutEvent contains the name of an event that Wheel::Run emits
322 whenever the child process writes something to its STDOUT filehandle.
323 In other words, whatever the child prints to STDOUT, the parent
324 receives a StdoutEvent---provided that the child prints something
325 compatible with the parent's StdoutFilter.
326
327 StdoutEvent comes with two parameters. "ARG0" contains the information
328 that the child wrote to STDOUT. "ARG1" holds the unique ID of the
329 wheel that read the output.
330
331 sub stdout_state {
332 my ($heap, $input, $wheel_id) = @_[HEAP, ARG0, ARG1];
333 print "Child process in wheel $wheel_id wrote to STDOUT: $input\n";
334 }
335
336 StderrEvent
337
338 StderrEvent behaves exactly as StdoutEvent, except for data the child
339 process writes to its STDERR filehandle.
340
341 StderrEvent comes with two parameters. "ARG0" contains the information
342 that the child wrote to STDERR. "ARG1" holds the unique ID of the
343 wheel that read the output.
344
345 sub stderr_state {
346 my ($heap, $input, $wheel_id) = @_[HEAP, ARG0, ARG1];
347 print "Child process in wheel $wheel_id wrote to STDERR: $input\n";
348 }
349
350 StdioFilter
351
352 StdioFilter, if used, must contain an instance of a POE::Filter
353 subclass. This filter describes how the parent will format put() data
354 for the child's STDIN, and how the parent will parse the child's
355 STDOUT.
356
357 If STDERR will also be parsed, then a separate StderrFilter will also
358 be needed.
359
360 StdioFilter defaults to a POE::Filter::Line instance, but only if both
361 StdinFilter and StdoutFilter are not specified. If either StdinFilter
362 or StdoutFilter is used, then StdioFilter is illegal.
363
364 StdinFilter
365
366 StdinFilter may be used to specify a particular STDIN serializer that
367 is different from the STDOUT parser. If specified, it conflicts with
368 StdioFilter. StdinFilter's value, if specified, must be an instance of
369 a POE::Filter subclass.
370
371 Without a StdinEvent, StdinFilter is illegal.
372
373 StdoutFilter
374
375 StdoutFilter may be used to specify a particular STDOUT parser that is
376 different from the STDIN serializer. If specified, it conflicts with
377 StdioFilter. StdoutFilter's value, if specified, must be an instance
378 of a POE::Filter subclass.
379
380 Without a StdoutEvent, StdoutFilter is illegal.
381
382 StderrFilter
383
384 StderrFilter may be used to specify a filter for a child process'
385 STDERR output. If omitted, POE::Wheel::Run will create and use its own
386 POE::Filter::Line instance, but only if a StderrEvent is specified.
387
388 Without a StderrEvent, StderrFilter is illegal.
389
390 Group
391
392 Group contains a numeric group ID that the child process should run
393 within. By default, the child process will run in the same group as
394 the parent.
395
396 Group is not fully portable. It may not work on systems that have no
397 concept of user groups. Also, the parent process may need to run with
398 elevated privileges for the child to be able to change groups.
399
400 User
401
402 User contains a numeric user ID that should own the child process. By
403 default, the child process will run as the same user as the parent.
404
405 User is not fully portable. It may not work on systems that have no
406 concept of users. Also, the parent process may need to run with
407 elevated privileges for the child to be able to change users.
408
409 NoSetSid
410
411 When true, NoSetSid disables setsid() in the child process. By
412 default, the child process calls setsid() is called so that it may
413 execute in a separate UNIX session.
414
415 NoSetPgrp
416
417 When true, NoSetPgrp disables setprgp() in the child process. By
418 default, the child process calls setpgrp() to change its process group,
419 if the OS supports that.
420
421 setsid() is used instead of setpgrp() if Conduit is pty or pty-pipe.
422 See "NoSetSid".
423
424 Priority
425
426 Priority adjusts the child process' niceness or priority level,
427 depending on which (if any) the underlying OS supports. Priority
428 contains a numeric offset which will be added to the parent's priority
429 to determine the child's.
430
431 The priority offset may be negative, which in UNIX represents a higher
432 priority. However UNIX requires elevated privileges to increase a
433 process' priority.
434
435 Program
436
437 Program specifies the program to exec() or the block of code to run in
438 the child process. Program's type is significant.
439
440 If Program holds a scalar, its value will be executed as
441 exec($program). Shell metacharacters are significant, per exec(SCALAR)
442 semantics.
443
444 If Program holds an array reference, it will executed as
445 exec(@$program). As per exec(ARRAY), shell metacharacters will not be
446 significant.
447
448 If Program holds a code reference, that code will be called in the
449 child process. This mode allows POE::Wheel::Run to execute long-
450 running internal code asynchronously, while the usual modes execute
451 external programs. The child process will exit after that code is
452 finished, in such a way as to avoid DESTROY and END block execution.
453 See "Coderef Execution Side Effects" for more details.
454
455 perlfunc has more information about exec() and the different ways to
456 call it.
457
458 Please avoid calling exit() explicitly when executing a subroutine.
459 The child process inherits all objects from the parent, including ones
460 that may perform side effects. POE::Wheel::Run takes special care to
461 avoid object destructors and END blocks in the child process, but
462 calling exit() will trigger them.
463
464 ProgramArgs
465
466 If specified, ProgramArgs should refer to a list of parameters for the
467 program being run.
468
469 my @parameters = qw(foo bar baz); # will be passed to Program
470 ProgramArgs => \@parameters;
471
472 event EVENT_TYPE => EVENT_NAME, ...
473 event() allows programs to change the events that Wheel::Run emits when
474 certain activities occurs. EVENT_TYPE may be one of the event
475 parameters described in POE::Wheel::Run's constructor.
476
477 This example changes the events that $wheel emits for STDIN flushing
478 and STDOUT activity:
479
480 $wheel->event(
481 StdinEvent => 'new-stdin-event',
482 StdoutEvent => 'new-stdout-event',
483 );
484
485 Undefined EVENT_NAMEs disable events.
486
487 put RECORDS
488 put() queues up a list of RECORDS that will be sent to the child
489 process' STDIN filehandle. These records will first be serialized
490 according to the wheel's StdinFilter. The serialized RECORDS will be
491 flushed asynchronously once the current event handler returns.
492
493 get_stdin_filter
494 get_stind_filter() returns the POE::Filter object currently being used
495 to serialize put() records for the child's STDIN filehandle. The
496 return object may be used according to its own interface.
497
498 get_stdout_filter
499 get_stdout_filter() returns the POE::Filter object currently being used
500 to parse what the child process writes to STDOUT.
501
502 get_stderr_filter
503 get_stderr_filter() returns the POE::Filter object currently being used
504 to parse what the child process writes to STDERR.
505
506 set_stdio_filter FILTER_OBJECT
507 Set StdinFilter and StdoutFilter to the same new FILTER_OBJECT.
508 Unparsed STDOUT data will be parsed later by the new FILTER_OBJECT.
509 However, data already put() will remain serialized by the old filter.
510
511 set_stdin_filter FILTER_OBJECT
512 Set StdinFilter to a new FILTER_OBJECT. Data already put() will remain
513 serialized by the old filter.
514
515 set_stdout_filter FILTER_OBJECT
516 Set StdoutFilter to a new FILTER_OBJECT. Unparsed STDOUT data will be
517 parsed later by the new FILTER_OBJECT.
518
519 set_stderr_filter FILTER_OBJECT
520 Set StderrFilter to a new FILTER_OBJECT. Unparsed STDERR data will be
521 parsed later by the new FILTER_OBJECT.
522
523 pause_stdout
524 Pause reading of STDOUT from the child. The child process may block if
525 the STDOUT IPC conduit fills up. Reading may be resumed with
526 resume_stdout().
527
528 pause_stderr
529 Pause reading of STDERR from the child. The child process may block if
530 the STDERR IPC conduit fills up. Reading may be resumed with
531 resume_stderr().
532
533 resume_stdout
534 Resume reading from the child's STDOUT filehandle. This is only
535 meaningful if pause_stdout() has been called and remains in effect.
536
537 resume_stderr
538 Resume reading from the child's STDERR filehandle. This is only
539 meaningful if pause_stderr() has been called and remains in effect.
540
541 shutdown_stdin
542 shutdown_stdin() closes the child process' STDIN and stops the wheel
543 from reporting StdinEvent. It is extremely useful for running
544 utilities that expect to receive EOF on STDIN before they respond.
545
546 ID
547 ID() returns the wheel's unique ID. Every event generated by a
548 POE::Wheel::Run object includes a wheel ID so that it can be matched to
549 the wheel that emitted it. This lets a single session manage several
550 wheels without becoming confused about which one generated what event.
551
552 ID() is not the same as PID().
553
554 PID
555 PID() returns the process ID for the child represented by the
556 POE::Wheel::Run object. It's often used as a parameter to sig_child().
557
558 PID() is not the same as ID().
559
560 kill SIGNAL
561 POE::Wheel::Run's kill() method sends a SIGNAL to the child process the
562 object represents. kill() is often used to force a reluctant program
563 to terminate. SIGNAL is one of the operating signal names present in
564 %SIG.
565
566 kill() returns the number of processes successfully signaled: 1 on
567 success, or 0 on failure, since the POE::Wheel::Run object only affects
568 at most a single process.
569
570 kill() sends SIGTERM if SIGNAL is undef or omitted.
571
572 get_driver_out_messages
573 get_driver_out_messages() returns the number of put() records remaining
574 in whole or in part in POE::Wheel::Run's POE::Driver output queue. It
575 is often used to tell whether the wheel has more input for the child
576 process.
577
578 In most cases, StdinEvent may be used to trigger activity when all data
579 has been sent to the child process.
580
581 get_driver_out_octets
582 get_driver_out_octets() returns the number of serialized octets
583 remaining in POE::Wheel::Run's POE::Driver output queue. It is often
584 used to tell whether the wheel has more input for the child process.
585
587 Execution Environment
588 It's common to scrub a child process' environment, so that only
589 required, secure values exist. This amounts to clearing the contents
590 of %ENV and repopulating it.
591
592 Environment scrubbing is easy when the child process is running a
593 subroutine, but it's not so easy---or at least not as intuitive---when
594 executing external programs.
595
596 The way we do it is to run a small subroutine in the child process that
597 performs the exec() call for us.
598
599 Program => \&exec_with_scrubbed_env,
600
601 sub exec_with_scrubbed_env {
602 delete @ENV{keys @ENV};
603 $ENV{PATH} = "/bin";
604 exec(@program_and_args);
605 }
606
607 That deletes everything from the environment and sets a simple, secure
608 PATH before executing a program.
609
610 Coderef Execution Side Effects
611 The child process is created by fork(), which duplicates the parent
612 process including a copy of POE::Kernel, all running Session instances,
613 events in the queue, watchers, open filehandles, and so on.
614
615 When executing an external program, the UNIX exec() call immediately
616 replaces the copy of the parent with a completely new program.
617
618 When executing internal coderefs, however, we must preserve the code
619 and any memory it might reference. This leads to some potential side
620 effects.
621
622 DESTROY and END Blocks Run Twice
623
624 Objects that were created in the parent process are copied into the
625 child. When the child exits normally, any DESTROY and END blocks are
626 executed there. Later, when the parent exits, they may run again.
627
628 POE::Wheel::Run takes steps to avoid running DESTROY and END blocks in
629 the child process. It uses POSIX::_exit() to bypass them. If that
630 fails, it may even kill() itself.
631
632 If an application needs to exit explicitly, for example to return an
633 error code to the parent process, then please use POSIX::_exit() rather
634 than Perl's core exit().
635
636 POE::Kernel's run() method was never called
637
638 This warning is displayed from POE::Kernel's DESTROY method. It's a
639 side effect of calling exit() in a child process that was started
640 before "POE::Kernel->run()" could be called. The child process
641 receives a copy of POE::Kernel where run() wasn't called, even if it
642 was called later in the parent process.
643
644 The most direct solution is to call POSIX::_exit() rather than exit().
645 This will bypass POE::Kernel's DESTROY, and the message it emits.
646
647 Running POE::Kernel in the Child
648
649 Calling "POE::Kernel->run()" in the child process effectively resumes
650 the copy of the parent process. This is rarely (if ever) desired.
651
652 More commonly, an application wants to run an entirely new POE::Kernel
653 instance in the child process. This is supported by first stop()ping
654 the copied instance, starting one or more new sessions, and calling
655 run() again. For example:
656
657 Program => sub {
658 # Wipe the existing POE::Kernel clean.
659 $poe_kernel->stop();
660
661 # Start a new session, or more.
662 POE::Session->create(
663 ...
664 );
665
666 # Run the new sessions.
667 POE::Kernel->run();
668 }
669
670 Strange things are bound to happen if the program does not call "stop"
671 in POE::Kernel before "run" in POE::Kernel. However this is vaguely
672 supported in case it's the right thing to do at the time.
673
675 POE::Wheel describes wheels in general.
676
677 The SEE ALSO section in POE contains a table of contents covering the
678 entire POE distribution.
679
681 POE::Wheel::Run's constructor should emit proper events when it fails.
682 Instead, it just dies, carps or croaks. This isn't necessarily bad; a
683 program can trap the death in new() and move on.
684
685 Priority is a delta, not an absolute niceness value.
686
687 It might be nice to specify User by name rather than just UID.
688
689 It might be nice to specify Group by name rather than just GID.
690
691 POE::Pipe::OneWay and Two::Way don't require the rest of POE. They
692 should be spun off into a separate distribution for everyone to enjoy.
693
694 If StdinFilter and StdoutFilter seem backwards, remember that it's the
695 filters for the child process. StdinFilter is the one that dictates
696 what the child receives on STDIN. StdoutFilter tells the parent how to
697 parse the child's STDOUT.
698
700 Please see POE for more information about authors and contributors.
701
702
703
704perl v5.12.1 2010-04-03 POE::Wheel::Run(3)