exec in CLI vs. mod_php

php.internals

Brian Moon

23 years ago
I am trying to figure out what is internally different about exec between CLI and mod_php. If exec() a script from CLI and said script forks, I get my prompt right back. test.php ------------ <?php exec("/home/brianm/fork.php"); ?> fork.php ------------ #!/usr/local/bin/php <?php $pid = pcntl_fork(); if ($pid == -1) { trigger_error("Could not fork __FILE__", E_USER_ERROR); exit(); } elseif($pid>0) { exit(); } touch("/tmp/file.txt"); sleep(5); ?> However, if I run test.php from mod_php in Apache, the parent zombies and exec() waits for the forked process to finish. What is the difference here and is there any hope of having exec in mod_php work the same as it does in CLI? Brian Moon dealnews.com

Wez Furlong

23 years ago
Under apache, you inherit all of the apache sockets when the libc forks and execs your script. This causes some problems (there are one or two bug reports about this in the bug db) with processes waiting around on the sockets. It looks like there was some code in the apache SAPI to avoid this problem, but it is currently commented out with an explanation that it is "problematic". I've asked about this problem a few times, but no one seems to notice my questions or have time to reply. So, we know of the problem, we know roughly how to fix it, but no one can explain why we can't fix it :) --Wez. On Thu, 29 May 2003, Brian Moon wrote:

Jani Taskinen

23 years ago
On Thu, 29 May 2003, Wez Furlong wrote:
>It looks like there was some code in the apache SAPI to avoid this >problem, but it is currently commented out with an explanation that it >is "problematic".
What code exactly..? Maybe ask that who commented out why it was problematic? --Jani

Zeev Suraski

23 years ago
At 22:44 29/05/2003, Wez Furlong wrote:
>Under apache, you inherit all of the apache sockets when the libc forks >and execs your script. > >This causes some problems (there are one or two bug reports about this >in the bug db) with processes waiting around on the sockets. > >It looks like there was some code in the apache SAPI to avoid this >problem, but it is currently commented out with an explanation that it >is "problematic". > >I've asked about this problem a few times, but no one seems to notice my >questions or have time to reply. > >So, we know of the problem, we know roughly how to fix it, but no one >can explain why we can't fix it :)
IIRC, it has to do with resources. For instance, if you close() a socket that's used by a MySQL link, it ended up breaking the link in the parent process. Did you try looking at the history to see whether there was any info in the commit message? Zeev

Wez Furlong

23 years ago
I think I did check, but there were no useful comments. if close()ing them before exec'ing is a problem, can't we just set the close-on-exec flag on the fd's ? This will cause the descriptors to be dup'd for the fork, and the duplicates to be closed when the child execs; in theory, that will leave the parent in a fit and healthy state. --Wez. On Fri, 30 May 2003, Zeev Suraski wrote:

Zeev Suraski

23 years ago
At 17:44 30/05/2003, Wez Furlong wrote:
>I think I did check, but there were no useful comments. >if close()ing them before exec'ing is a problem, can't we just set the >close-on-exec flag on the fd's ? > >This will cause the descriptors to be dup'd for the fork, and the >duplicates to be closed when the child execs; in theory, that will leave >the parent in a fit and healthy state.
This whole problem didn't add up to me - it didn't sound too logical to begin with. Anyway - after some archeological searches in my mailbox from 1998 (never erase email!) - here's the real reason. http://www.phpbuilder.com/mail/php3-list/199805/1391.php Zeev

Brian Moon

23 years ago
So, does this mean that because of FP, we are stuck? There is something sad about that. But, Brian Foddy emailed me a work around to my solution. | I don't know if this helps, or is restating the obvious... | Using 4.2.3 and apache 1.3.21 (php_mod) (yes, rather old combo, hopefully | this behavior hasn't changed in newer versions) I can | achieve what you want by | exec ($execute_cmd, $exec_array, $exec_return); | where $execute_cmd = "/apps/soc/paging/send_page.pl > /dev/null &"; | (a perl script). The web page returns immediately and the perl script | starts executing in the background until its finished. Unfortunately the | web user has no way to know when/if the script finishes or with what | status. | | Brian So, for now, I will pursue that method. Brian Moon dealnews.com ----- Original Message ----- From: "Zeev Suraski" <zeev@zend.com> To: "Wez Furlong" <wez@thebrainroom.com> Cc: "Brian Moon" <brianm@dealnews.com>; <internals@lists.php.net> Sent: Friday, May 30, 2003 9:54 AM Subject: Re: [PHP-DEV] exec in CLI vs. mod_php | At 17:44 30/05/2003, Wez Furlong wrote: | >I think I did check, but there were no useful comments. | >if close()ing them before exec'ing is a problem, can't we just set the | >close-on-exec flag on the fd's ? | > | >This will cause the descriptors to be dup'd for the fork, and the | >duplicates to be closed when the child execs; in theory, that will leave | >the parent in a fit and healthy state. | | This whole problem didn't add up to me - it didn't sound too logical to | begin with. Anyway - after some archeological searches in my mailbox from | 1998 (never erase email!) - here's the real reason. | | http://www.phpbuilder.com/mail/php3-list/199805/1391.php | | Zeev | | |

Wez Furlong

23 years ago
I *think* that in the case of Brian's question (which applies to the exec(), system() and so on family of PHP functions), we can safely loop throught the descriptors (except for those we will be using to capture or pass-thru the output) and set the close-on-exec flag prior to forking. I don't have the time to check this out right now, maybe next week; if anyone else wants to dive in a test my theory, go ahead :) --Wez. On Fri, 30 May 2003, Zeev Suraski wrote:

Zeev Suraski

23 years ago
At 18:02 30/05/2003, Wez Furlong wrote:
>I *think* that in the case of Brian's question (which applies to the >exec(), system() and so on family of PHP functions), we can safely loop >throught the descriptors (except for those we will be using to capture >or pass-thru the output) and set the close-on-exec flag prior to >forking.
Yep, but how do you know which ones are the ones you shouldn't touch? Zeev

Wez Furlong

23 years ago
For exec() and system(), we don't send any input and only capture stdout. So, everything except the stdout fileno can be closed-on-exec. The user can do the usual 2>&1 trick to get the stderr output as we run their command using the shell. --Wez. On Fri, 30 May 2003, Zeev Suraski wrote:

Zeev Suraski

23 years ago
At 18:18 30/05/2003, Wez Furlong wrote:
>For exec() and system(), we don't send any input and only capture >stdout. So, everything except the stdout fileno can be closed-on-exec. >The user can do the usual 2>&1 trick to get the stderr output as we run >their command using the shell.
Unless I'm missing something, the post I sent illustrates an example where a file descriptor other than 0/1/2 is being used to communicate between the parent process and the child process. I don't think that close-on-exec on the fd's before exec() is any different than simply close()ing before we exec(), so I think that this five year old issue would surface if we go for that solution. Back then, we couldn't come up with a good solution for this issue, and we simply disabled closing fd's on exec. We could alter this behavior to be optional, through php.ini, and yes, I don't particularly like this solution either, but I don't have any better in mind right now... Zeev