Jos Backus <[EMAIL PROTECTED]> writes:

> OK, so we only fork if we are a pgrp leader. Since whether or not to fork is
> the only thing NO_DETACH controls and since this decision is now to be based
> on the process' pgrp leader status, it seems that NO_DETACH has become
> obsolete as we can determine this automatically: when httpd is run by the
> shell, it's a pgrp leader so we fork; if run by a process controller, it's not
> a pgrp leader so we don't fork.

This assumption is dangerous and incorrect. You're overlooking the
interaction between sessions, process groups, and shells with and
without job control.

httpd calls setsid(2) not only to create a new process group and
become its leader, but to escape the current session and controlling
terminal. setsid(2) has to be called regardless of whether we want
the main httpd to double-fork away from its parent, to get away
from the controlling terminal. You can't call setsid(2) if you're
already process group leader.

However, when you invoke httpd under a shell with job control (e.g.
bash), it is automatically put into a new process group as the leader:

Starting under Solaris /bin/sh without job control:

# ps -o uid,pid,ppid,pgid,sid,comm
  UID   PID  PPID  PGID   SID COMMAND
    0 20240 20238 20240 20240 -sh
    0 20255 20240 20240 20240 ps
# ./test
pid = 20256, pgrp = 20240, sid = 20240

We're a member of the parent shell's process group, but not the leader,
and thus can setsid(2).

Starting under bash with job control:

# bash
root@build1:~# ps -o uid,pid,ppid,pgid,sid,comm
  UID   PID  PPID  PGID   SID COMMAND
    0 20251 20250 20251 20240 ps
    0 20240 20238 20240 20240 -sh
    0 20250 20240 20250 20240 bash
root@build1:~# ./test
pid = 20252, pgrp = 20252, sid = 20240

We're a member of our OWN process group AND the leader, and thus can't
setsid(2).

This is the reason that httpd forks before calling setsid(2) -- so
that in case it was run under a shell with job control and was made
process group leader, it's not process group leader anymore, because
its parent is, or rather was, before it exited). [1] Thus, if httpd
is started from a shell with job control, it MUST fork(2) at least
once before calling setsid(2).

Note that this means that our non-forking process supervisor mode
for httpd will never work if httpd is invoked from a shell with job
control. I think this is a reasonable restriction, as long as it's
properly noted in the documentation.

Now, Jos' assumption above is dangerous because if you're invoked
from a system startup script that runs under a shell without job
control, e.g.  Solaris /bin/sh, you're not going to be process group
leader. Under the logic above, it wouldn't daemonize, and the system
startup script would never exit, and system startup would hang
forever. (Hope you started sshd before httpd. :))

I don't believe that there's any portable or reliable way for httpd
to detect whether whether it's being run under a 'process controller'
or not. As I've just shown above, whether it's a process group
leader already is not reliable. Thus, we need to make httpd
have a normal mode (daemonize), with a command line switch to disable
this behavior (-DWHATEVER) if a sysadmin wants to run httpd under
a process controller.

I also wouldn't mind if someone took a look at my patch for apache 1.3.22
to accomplish this same issue. :)

        http://bugs.apache.org/index.cgi/full/9341

Thanks for your consideration.

--michael

[1] Stevens, _Unix Network Programming, Volume One_ (2nd Edition),
pp 335: "We first call fork(2) and then the parent terminates and the
child continues. [...] Also, the child inherits the process group
ID from the parent but gets its own process ID. This guarantees
that the child is not a process group leader, which is required for
the next call to setsid(2)."

-- 
[EMAIL PROTECTED] (michael handler)                           washington, dc

Reply via email to