Apologies in advance that this post has got a bit longer than I expected
when I started ...
I'm using Wheel::Run to run a program in a child process and catch stdout
and stderr. This works fine when the program is run in a terminal, but
when I daemonize it using Proc::Daemon, something strange happens -- the
stdout and stderr from the child "disappears". I've searched the archives
and the effect is the same as that described by Matthew Hicks in a thread
of similar name back in Sept 2005, and I've found that his solution also
works for me (edit Proc::Daemon to change it to stop it re-opening STDIN
to /dev/null. I also found I had to stop it reopening STDERR as well).
I also see it's in the bug list as #16691 (from Chris Fedde, with a
different work around).
This prompted me to try a third course of action: change Proc::Daemon so
it only runs POSIX::close for file descriptors 3 and up and not for 0, 1,
2. Change:
foreach $i (0 .. OpenMax) { POSIX::close($i); }
to
foreach $i (3 .. OpenMax) { POSIX::close($i); }
This also fixes the problem, so I'm guessing that there's some interaction
between POSIX::close and a subsequent perl open that causes the problem.
(The perl FAQ makes no mention of POSIX::close in its section on
daemonization).
Not sure if this is a Linux thing or what? (I'm using RHEL3, perl 5.8.0,
POE 0.33).
However, in the course of investigating this, I've found a simple
illustration of the problem. I started with the "Child Processes 2"
example from the cookbook
(http://poe.perl.org/?POE_Cookbook/Child_Processes_2). This example runs
"ls -1 /" as the child.
I added the following 6 lines before the POE::Session->create:
use Proc::Daemon;
# Proc::Daemon::init();
open STDOUT, ">$ENV{HOME}/xx.stdout" or die "!
$ENV{HOME}/xx.stdout : $!";
open STDERR, ">$ENV{HOME}/xx.stderr" or die "!
$ENV{HOME}/xx.stderr : $!";
open O, ">$ENV{HOME}/xx.log" or die "! $ENV{HOME}/xx.log : $!";
select O; $| = 1;
I also added another argument to the program that's run to make it give an
error message on stderr, so it now reads:
( Program => [ "/bin/ls", "-1", "/", "/non-exist" ], # Program to
run.
When I run it, it produces the listing of / in xx.log. The lines are
prefixed by "STDOUT: ", showing that they were written by the
got_child_stdout() event handler and the error line for /non-exist is
prefixed "STDERR: ". xx.stdout is an empty file and xx.stderr contains a
line "Child process PID:xxx reaped:".
If I uncomment the Proc::Daemon::init() line and run again, the effect is
different. This time, xx.log just contains the line "child closed." (from
the got_child_close() event handler). xx.stdout contains the ls of /. And
xx.stderr contains a whole load of lines saying "Child process PID:0
reaped:" (over 88000 of them in one case, over 1400 on another machine).
The error line for /non-exist is buried in the middle somewhere and the
file ends with the reaped message for the real child pid.
This seems to imply that somehow the child gets the original
pre-daemonization stdout and stderr, although I'm not sure how, after
they've been POSIX::closed and re-opened in Proc::Daemon and then piped by
Wheel::Run. And it seems that waitpid() keeps returning 0 (instead of -1?)
in Resources/Signals.pm, l.156.
Anyway, applying any of the 3 changes above, fixes the problem.
best regards, John Escott.