On Wed, May 26, 2004 at 09:39:23PM +0100, Niall O Broin wrote:
> The Perl program appears to be doing all the right things - I don't wait for
> my child with $SIG{CHLD} = 'IGNORE' and I have autoflushing set on with
> $| = 1 and sure enough, when I run the program from a terminal (with the
> exact same command line as PHP uses with system() ) it takes a couple of
> seconds to run, returns the correct output, and ends and ps then shows it's
> abandoned child still running with a parent of 1 just as it should.
>> Yet when I do this from the PHP page, PHP doesn't finish until both parent and
> child have finished.
(I didn't see this mail until today; hopefully the reply isn't too late
to be of use.)
Taken from http://ie.php.net/manual/en/function.system.php :
"Note: If you start a program using this function and want to leave it
running in the background, you have to make sure that the output of that
program is redirected to a file or some other output stream or else PHP
will hang until the execution of the program ends."
PHP creates a pipe, forks, the child dups stdout (and probably stderr)
to the pipe and execs your program, the parent reads from the pipe,
waits for the pipe to be closed, _then_ calls waitpid to clean up the
child process. The child process (your Perl program, after being
exec'd) forks, does stuff and exits, the grandchild process hangs around
with stdout (and probably stderr) still open, so the PHP parent process
doesn't see the pipe closing until the grandchild process exits, and
thus doesn't call waitpid until the grandchild process exits.
> When I deliberately delay the parent's death a little and run the perl program
> from the command line, I see just what I'd expect to see in a ps listing -
> two copies of the perl program, parent and child. When the parent dies, the
> child is adopted by init, just as I expect.
This is because the shell just calls waitpid, ignoring output from
child/grandchild processes.
> However, when I run it from php it's a little different. I see both processes
> running, but when the parent SHOULD end it stays in the process list showing
> <defunct> until such time as its child dies, yet while it's showing <defunct>
> its child is showing a PPID of 1 so it has been adopted by init as expected.
PHP doesn't call waitpid until the pipe is closed (there's no point),
and the default action on receiving SIGCHLD is to ignore it, so the
child process isn't reaped by PHP until the grandchild process
exits/closes the pipe.
> However, for some reason it won't die until its child does, which of course is
> somewhat defeating the point of having the blooming thing fork in the first
> place. Any ideas?
Redirect stdout and stderr.
--
John Tobin
"Windows seems to take the position that since things in the kernel
are defined as secure, you should put everything in the kernel. When
they can't figure out how to secure something, they just put it in the
kernel and define it as secure." -- Bruce Schneier, Secrets and Lies
Maintained by the ILUG website team. The aim of Linux.ie is to
support and help commercial and private users of Linux in Ireland. You can
display ILUG news in your own webpages, read backend
information to find out how. Networking services kindly provided by HEAnet, server kindly donated by
Dell. Linux is a trademark of Linus Torvalds,
used with permission. No penguins were harmed in the production or maintenance
of this highly praised website. Looking for the
Indian Linux Users' Group? Try here. If you've read all this and aren't a lawyer: you should be!