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, 
            &current_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, 
  -                 &current_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, 
&current_live_processes);
            APD2("main_process: child in slot %d died", rv);
  -         if (processes_to_create) {
  -             create_process(process_handles, process_kill_events, 
&current_live_processes, 
  -                     &child_num, signal_prefix_string, argc, argv);
  -             processes_to_create--;
  -         }
  +            if (create_process(process_handles, process_kill_events, 
&current_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, 
&current_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, 
&current_live_processes, 
  -                 &child_num, signal_prefix_string, argc, argv);
  +             if (create_process(process_handles, process_kill_events, 
&current_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;
  
  
  

Reply via email to