John Escott (Thu 02/23/06 19:20): > 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. >
I definitely see the same behaviour on both RHEL3/5.8.7 and FreeBSD/5.8.8. However, non-daemonized and daemonized outputs are identical using Net::Server::Daemonize which is what I've always used for this sort of thing. Zach