Re: run an interactive command using POE::Wheel?
[email protected] ("woosley. xu.")
| Newsgroups | perl.poe |
|---|---|
| Message-ID | <[email protected]> |
Thanks, Olivier,
Finally I can get the script working except one problem left: How can I reap
child process?
Below is my code. If I input CTRL-C when the script asking for a username or
password, the script dose not exit even if I use $SIG{CHLD}='IGNORE'. By 'ps
-ef', I can see that the get_name.pl is in the state of "zombie" and
waiting for the parent process to reap.
$|++;
use POE qw( Wheel::ReadLine Wheel::Run );
*POE::Kernel::USE_SIGCHLD = sub (){1};
$SIG{CHLD} = 'ignore';
POE::Session->create(
inline_states => {
_start => \&on_start,
got_child_stdout => \&on_child_stdout,
got_child_stderr => \&on_child_stderr,
got_child_close => \&on_child_close,
got_child_signal => \&on_child_signal,
got_user_input => \&read_from,
}
);
POE::Kernel->run();
exit 0;
sub on_start {
$_[HEAP]->{stdin} =
POE::Wheel::ReadLine->new(InputEvent => 'got_user_input');
my $consol = $_[HEAP]->{stdin};
$_[HEAP]->{job} = POE::Wheel::Run->new(
Program => ["perl get_name.pl"],
StdoutEvent => "got_child_stdout",
StderrEvent => "got_child_stderr",
CloseEvent => "got_child_close",
StdioFilter => POE::Filter::Line->new(),
StderrFilter => POE::Filter::Line->new(),
Conduit => 'pty',
);
my $child = $_[HEAP]->{job};
my $pid = $child->PID;
$_[KERNEL]->sig_child("$pid, got_child_signal");
$_[HEAP]->{stdin}->put("Child pid $pid, started as wheel , $pid");
}
sub on_child_stdout {
my ($stdout_line) = @_[ARG0];
my $child = $_[HEAP]{job};
my $pid = $child->PID;
$_[HEAP]->{stdin}->put("pid $pid, STDOUT: $stdout_line");
$_[HEAP]->{stdin}->get("");
}
sub on_child_close {
my $wheel_id = $_[ARG0];
my $child = delete $_[HEAP]{job};
unless (defined $child) {
$_[HEAP]->{stdin}->put("wid $wheel_id closed all pipes.\n");
return;
}
}
sub on_child_signal {
$_[HEAP]->{stdin}->put("pid $_[ARG1] exited with status $_[ARG2].\n");
my $child = delete $_[HEAP]{job};
# May have been reaped by on_child_close() .
return unless defined $child;
delete $_[HEAP]{children_by_wid}{$child->ID};
}
sub read_from {
my ($input, $exception) = @_[ARG0, ARG1];
my $console = $_[HEAP]->{stdin};
my $job = $_[HEAP]->{job};
unless (defined $input) {
$console->put("Exception got, existing....");
$job && $job->kill();
return;
}
$_[HEAP]->{stdin}->put("got: $input");
$_[HEAP]->{job}->put($input);
}
2009/9/26 Olivier Mengué <[email protected]>
> 2009/9/25 woosley. xu. <[email protected]>
>
> > besides, if you write the interactive code like this:
> >
> > my $user = <STDIN>;
> > chomp $user;
> > $_[HEAP]->{job}->put("$user");
> > my $pass = <STDIN>;
> > chomp $pass;
> > $_[HEAP]->{job}->put("$pass");
> >
> > It won't pop up all the message from the child process until you finished
> > all your input. Maybe this is not the right way to do it, I am wondering
> > which is the way.
> >
> > You should do user input in the POE way too: by watching events coming
> from
> STDIN.
> Maybe POE::Wheel::ReadLine is what you need.
>
> Olivier.
>
--
Woosley.Xu
Tju->PMO->Rdps