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.

Reply via email to