stoddard 99/05/21 09:49:09
Modified: src/main http_main.c
Log:
Win32 cleanup:
1. Eliminate unnecessary (I hope :-) call to wait_for_multiple_objects
2. Clean up parent process code that handles shutdown and restart signals
3. Honor shutdown and restart events immediately, even it it means loosing
connections in the TCP stack's listen queue. Restarts triggered by
MaxRequestPerChild will caue the child process to handle all connections in the
listen queue before exiting.
PR: 3815
Revision Changes Path
1.437 +68 -54 apache-1.3/src/main/http_main.c
Index: http_main.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/main/http_main.c,v
retrieving revision 1.436
retrieving revision 1.437
diff -u -r1.436 -r1.437
--- http_main.c 1999/05/07 00:38:11 1.436
+++ http_main.c 1999/05/21 16:49:08 1.437
@@ -5264,7 +5264,7 @@
* we are restricted to a maximum of 64 threads. This is a simplistic
* routine that will increase this size.
*/
-DWORD wait_for_many_objects(DWORD nCount, CONST HANDLE *lpHandles,
+static DWORD wait_for_many_objects(DWORD nCount, CONST HANDLE *lpHandles,
DWORD dwSeconds)
{
time_t tStopTime;
@@ -5457,38 +5457,27 @@
my_pid, total_jobs, start_exit);
#endif
if ((max_jobs_per_exe && (total_jobs > max_jobs_per_exe) &&
!start_exit)) {
+ /* When MaxRequestsPerChild is hit, handle everything on the
stack's
+ * listen queue before exiting. This may take a while if the
server
+ * is really busy.
+ */
start_exit = 1;
wait_time = 1;
ap_release_mutex(start_mutex);
start_mutex_released = 1;
APD2("process PID %d: start mutex released\n", my_pid);
}
- if (!start_exit) {
- rv = WaitForSingleObject(exit_event, 0);
- ap_assert((rv == WAIT_TIMEOUT) || (rv == WAIT_OBJECT_0));
- if (rv == WAIT_OBJECT_0) {
- APD1("child: exit event signalled, exiting");
- start_exit = 1;
- /* Lets not break yet - we may have threads to clean up */
- /* break;*/
- }
- rv = wait_for_many_objects(nthreads, child_handles, 0);
- ap_assert(rv != WAIT_FAILED);
- if (rv != WAIT_TIMEOUT) {
- rv = rv - WAIT_OBJECT_0;
- ap_assert((rv >= 0) && (rv < nthreads));
- cleanup_thread(child_handles, &nthreads, rv);
- break;
- }
- }
+ /* Always check for the exit event being signaled. Honor the exit
event,
+ * even if it means loosing connections in the stack's listen queue.
+ */
+ rv = WaitForSingleObject(exit_event, 0);
+ ap_assert((rv == WAIT_TIMEOUT) || (rv == WAIT_OBJECT_0));
+ if (rv == WAIT_OBJECT_0) {
+ APD1("child: exit event signalled, exiting");
+ start_exit = 1;
+ break;
+ }
-#if 0
- /* Um, this made us exit before all the connections in our
- * listen queue were dealt with.
- */
- if (start_exit && max_jobs_after_exit_request && (count_down-- < 0))
- break;
-#endif
tv.tv_sec = wait_time;
tv.tv_usec = 0;
@@ -5705,7 +5694,7 @@
#define MAX_PROCESSES 50 /* must be < MAX_WAIT_OBJECTS-1 */
-void cleanup_process(HANDLE *handles, HANDLE *events, int position, int
*processes)
+static void cleanup_process(HANDLE *handles, HANDLE *events, int position,
int *processes)
{
int i;
int handle = 0;
@@ -5724,7 +5713,7 @@
APD4("cleanup_processes: removed child in slot %d handle %d, max=%d",
position, handle, *processes);
}
-int create_process(HANDLE *handles, HANDLE *events, int *processes, int
*child_num, char *kill_event_name, int argc, char **argv)
+static int create_process(HANDLE *handles, HANDLE *events, int *processes,
int *child_num, char *kill_event_name, int argc, char **argv)
{
int i = *processes;
HANDLE kill_event;
@@ -5810,6 +5799,9 @@
"ap%d", getpid());
setup_signal_names(signal_prefix_string);
+ /* Create shutdown event, apPID_shutdown, where PID is the parent
+ * Apache process ID. Shutdown is signaled by 'apache -k shutdown'.
+ */
signal_shutdown_event = CreateEvent(sa, TRUE, FALSE,
signal_shutdown_name);
if (!signal_shutdown_event) {
ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf,
@@ -5818,6 +5810,10 @@
exit(1);
}
APD2("master_main: created event %s", signal_shutdown_name);
+
+ /* Create restart event, apPID_restart, where PID is the parent
+ * Apache process ID. Restart is signaled by 'apache -k restart'.
+ */
signal_restart_event = CreateEvent(sa, TRUE, FALSE, signal_restart_name);
if (!signal_restart_event) {
CloseHandle(signal_shutdown_event);
@@ -5829,6 +5825,10 @@
CleanNullACL((void *)sa);
APD2("master_main: created event %s", signal_restart_name);
+ /* Create the start mutex, apPID, where PID is the parent Apache process
ID.
+ * Ths start mutex is used during a restart to prevent more than one
+ * child process from entering the accept loop at once.
+ */
start_mutex = ap_create_mutex(signal_prefix_string);
ev = (event **) alloca(sizeof(event *) * nchild);
child = (int *) alloca(sizeof(int) * (nchild+1));
@@ -5837,6 +5837,8 @@
service_set_status(SERVICE_START_PENDING);
if (create_process(process_handles, process_kill_events,
¤t_live_processes, &child_num, signal_prefix_string, argc,
argv) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
+ "master_main: create child process failed.
Exiting.");
goto die_now;
}
}
@@ -5863,23 +5865,16 @@
/* Wait for either a child process to die, or for the stop_event
* to be signalled by the service manager or rpc server */
while (1) {
+ if (current_live_processes == 0) {
+ ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO, server_conf,
+ "master_main: no child processes. Exiting.");
+ goto die_now;
+ }
+
/* Next line will block forever until either a child dies, or we
* get signalled on the "apache-signal" event (e.g. if the user is
* requesting a shutdown/restart)
*/
- if (current_live_processes == 0) {
- /* Shouldn't happen, but better safe than sorry */
- ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO, server_conf,
- "master_main: no child processes alive! creating one");
- if (create_process(process_handles, process_kill_events,
- ¤t_live_processes, &child_num, signal_prefix_string,
- argc, argv) < 0) {
- goto die_now;
- }
- if (processes_to_create) {
- processes_to_create--;
- }
- }
process_handles[current_live_processes] = signal_shutdown_event;
process_handles[current_live_processes+1] = signal_restart_event;
rv = WaitForMultipleObjects(current_live_processes+2, (HANDLE
*)process_handles,
@@ -5924,14 +5919,21 @@
shutdown_pending, restart_pending);
break;
}
+
+ /* Child process must have exited because of MaxRequestPerChild
being hit
+ * or a fatal error condition (seg fault, etc.). Remove the dead
process
+ * from the process_handles and process_kill_events table and
create a new
+ * child process.
+ */
ap_assert(cld < current_live_processes);
cleanup_process(process_handles, process_kill_events, cld,
¤t_live_processes);
APD2("main_process: child in slot %d died", rv);
- if (processes_to_create) {
- create_process(process_handles, process_kill_events,
¤t_live_processes,
- &child_num, signal_prefix_string, argc, argv);
- processes_to_create--;
- }
+ if (create_process(process_handles, process_kill_events,
¤t_live_processes,
+ &child_num, signal_prefix_string, argc, argv)
< 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
+ "master_main: Internally signaled restart
failed. Exiting.");
+ goto die_now;
+ }
}
if (!shutdown_pending && !restart_pending) {
ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO, server_conf,
@@ -5952,20 +5954,32 @@
int children_to_kill = current_live_processes;
APD1("--- Doing graceful restart ---");
+ /* Signal the child process to die.. */
+ for (i = 0; i < children_to_kill; i++) {
+ APD3("main process: signalling child #%d handle %d to die", i,
process_handles[i]);
+ if (SetEvent(process_kill_events[i]) == 0)
+ ap_log_error(APLOG_MARK,APLOG_WIN32ERROR, server_conf,
+ "SetEvent for child process in slot #%d", i);
+ /* Note: We are not guaranteeing the child process is
actually going to die.
+ * Could insert a WaitForMultipleObjects() with a timeout
followed by a
+ * TerminateProcess().
+ */
+ /* Remove the process (and event) from the process table */
+ cleanup_process(process_handles, process_kill_events, i,
¤t_live_processes);
+ }
+ /* Create a new child process */
processes_to_create = nchild;
for (i = 0; i < nchild; ++i) {
if (current_live_processes >= MAX_PROCESSES)
break;
- create_process(process_handles, process_kill_events,
¤t_live_processes,
- &child_num, signal_prefix_string, argc, argv);
+ if (create_process(process_handles, process_kill_events,
¤t_live_processes,
+ &child_num, signal_prefix_string, argc,
argv) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
+ "master_main: Externally signaled restart
failed. Exiting.");
+ goto die_now;
+ }
processes_to_create--;
- }
- for (i = 0; i < children_to_kill; i++) {
- APD3("main process: signalling child #%d handle %d to die", i,
process_handles[i]);
- if (SetEvent(process_kill_events[i]) == 0)
- ap_log_error(APLOG_MARK,APLOG_WIN32ERROR, server_conf,
- "SetEvent for child process in slot #%d", i);
}
}
++ap_my_generation;