Colm:

>>    The worker and event MPMs would use these to track their
>> non-worker threads; and the parent process for these MPMs could
>> monitor them as per option C to decide when the child process's
>> workers were ready to be counted.
> 
> +1, I think this could be very useful, I came accross the same kind of
> problems when looking at handling the odd mod_cgid race conditions when
> doing graceful stops, but in the end didn't solve them (we still have
> slightly different death semantics between prefork and worker-like MPM's
> for cgi termination).

   Great, I'll get started on this first thing tomorrow.  I'm
away Thurs-Mon this week but with luck will have some patches
before I go for all these co-mingled issues.

>>    Finally, a question without checking the code first ... I notice
>> that worker.c has the following, taken from prefork.c:
>> 
>>     /* fork didn't succeed. Fix the scoreboard or else
>>      * it will say SERVER_STARTING forever and ever
>>      */
>>     ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, NULL);
>> 
>> Is that right?  Should it perhaps cycle through and set all
>> non-DEAD workers to DEAD?  I'm thinking that in prefork,
>> threads_limit is set to 1, so mod_status only checks the first
>> thread in a slot, but here it'll check all of them.
> 
> I'm not sure what you mean. As in, all potential workers globally? That
> child isn't going to have any actual workers, since child_main() never
> got run.

   What I noticed is that the prefork MPM seems to consistently
use the first worker_score in the scoreboard for all its record-
keeping; that makes sense because its thread_limit is always 1.
So in make_child(), it sets that worker_score to SERVER_STARTING,
does the fork(), and if that fails, resets the worker_score
to SERVER_DEAD.  No problems there.

   However, the code seems to have been copied over into the
worker MPM, and that particular if-fork()-fails bit still does
the same business, even though other things have changed around
it.  In particular, multiple worker_score structures are in
use for each child (ap_threads_per_child of them), and
make_child() doesn't begin by setting them all to SERVER_STARTING --
or even one of them -- so having it subsequently handle the
fork()-fails error condition by resetting the first one to
SERVER_DEAD seems incorrect.

   Further, make_child() may be creating a child to replace
a gracefully exiting one, and if so, it shouldn't actually
touch any of the worker_score statuses.  That's because what
start_threads() in the child does -- in the case where fork()
succeeds -- is to watch for threads in the old process that
have marked their status as SERVER_GRACEFUL and only then
initiate new workers to replace them.  So in fact, if fork()
fails, such old workers may still be executing and their
status values may not yet be SERVER_GRACEFUL.  As things stand,
if one of them happens to be have a scoreboard index of 0, its
value will get overwritten by make_child().

   I think probably the right thing is for make_child() just
to do nothing here.  That makes the same assumption the rest
of the code does, namely, that worker threads will reach their
normal termination and set their statuses to SERVER_DEAD or
SERVER_GRACEFUL; and if a child process does fail, then
the parent process's will notice in server_main_loop() and
set all of the child's threads' statuses to SERVER_DEAD.

   Anyway, I'll include that change in my patchset for review;
I may of course have missed something important.

Chris.

-- 
GPG Key ID: 366A375B
GPG Key Fingerprint: 485E 5041 17E1 E2BB C263  E4DE C8E3 FA36 366A 375B

Reply via email to