Changes with Apache 1.3.23
+ *) Win32: The Apache Win32 developers generally recommend that
+ MaxRequestsPerChild be set to 0 to prevent the child process
+ from ever recycling. However, for those that do require a
+ non-zero setting, this patch fixes a serious bug that can cause
+ an apparent 'server-hang' condition where the server stops
+ responding to requests for a period of time. Prior to this
+ fix, when the child process handled MaxRequestsPerChild
+ connnections, the child process would stop accepting new
+ connections and begin allowing inactive threads to exit. The
+ problem was that a new process would not be created to begin
+ handling requests until the old process fully exited. The old
+ process can take an indeterminate amount of time to exit because
+ it may be sending large responses to clients connected over slow
+ links, or it may have threads blocked in read awaiting requests
+ (eg, one attack mode of the Nimda worm is to establish a
+ connection to the server but not send an HTTP request. This
+ connection will be timed out according to the setting of the
+ Timeout directive, 300 seconds). This fix allows the new process
+ to be immediately started and begin accepting requests when the
+ old child process reaches MaxRequestsPerChild.
+ [Bill Stoddard]
+
*) Win32: Emit error message when the server bumps up against the
ThreadsPerChild configuration limit. This will be useful for
admins to detect when their server is running out of threads
if (!reported && (active_threads == ap_threads_per_child)) {
reported = 1;
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
- "server reached ThreadsPerChild setting, consider"
- " raising the ThreadsPerChild setting");
+ "Server ran out of threads to serve requests. Consider "
+ "raising the ThreadsPerChild setting");
}
return (sock);
}
while (1) {
if (max_jobs_per_exe && (total_jobs > max_jobs_per_exe)) {
- /* MaxRequestsPerChild hit...
+ /* Reached MaxRequestsPerChild. Stop accepting new connections
+ * and signal the parent to start a new child process.
*/
+ ap_start_restart(1);
break;
}
/* Always check for the exit event being signaled.
}
break;
} else if (cld == current_live_processes+1) {
- /* apPID_restart event signalled, restart the child process */
+ /* apPID_restart event signalled.
+ * Signal the child to shutdown and start a new child process.
+ * The restart event can be signaled by a command line restart or
+ * by the child process when it handles MaxRequestPerChild connections.
+ */
int children_to_kill = current_live_processes;
restart_pending = 1;
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
/* Remove the process (and event) from the process table */
cleanup_process(process_handles, process_kill_events, i, ¤t_live_processes);
}
- processes_to_create = nchild;
+ processes_to_create = 1;
++ap_my_generation;
continue;
} else {
- /* A 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.
+ /* The child process exited premeturely because of a fatal error condition
+ * (eg, seg fault). Cleanup and restart the child process.
*/
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
- "master_main: Child processed exited (due to MaxRequestsPerChild?). Restarting the child process.");
+ "master_main: Child processed exited prematurely. Restarting the 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);