📄 mpm_winnt.c
字号:
return -1; } /* Create the child_exit_event */ hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!hExitEvent) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, "Parent: Could not create exit event for child process"); apr_pool_destroy(ptemp); CloseHandle(waitlist[waitlist_ready]); return -1; } if (!env) { /* Build the env array, only once since it won't change * for the lifetime of this parent process. */ int envc; for (envc = 0; _environ[envc]; ++envc) { ; } env = malloc((envc + 2) * sizeof (char*)); memcpy(env, _environ, envc * sizeof (char*)); apr_snprintf(pidbuf, sizeof(pidbuf), "AP_PARENT_PID=%i", parent_pid); env[envc] = pidbuf; env[envc + 1] = NULL; } rv = apr_proc_create(&new_child, cmd, args, env, attr, ptemp); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, "Parent: Failed to create the child process."); apr_pool_destroy(ptemp); CloseHandle(hExitEvent); CloseHandle(waitlist[waitlist_ready]); CloseHandle(new_child.hproc); return -1; } ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Parent: Created child process %d", new_child.pid); if (send_handles_to_child(ptemp, waitlist[waitlist_ready], hExitEvent, start_mutex, ap_scoreboard_shm, new_child.hproc, new_child.in)) { /* * This error is fatal, mop up the child and move on * We toggle the child's exit event to cause this child * to quit even as it is attempting to start. */ SetEvent(hExitEvent); apr_pool_destroy(ptemp); CloseHandle(hExitEvent); CloseHandle(waitlist[waitlist_ready]); CloseHandle(new_child.hproc); return -1; } /* Important: * Give the child process a chance to run before dup'ing the sockets. * We have already set the listening sockets noninheritable, but if * WSADuplicateSocket runs before the child process initializes * the listeners will be inherited anyway. */ waitlist[waitlist_term] = new_child.hproc; rv = WaitForMultipleObjects(2, waitlist, FALSE, INFINITE); CloseHandle(waitlist[waitlist_ready]); if (rv != WAIT_OBJECT_0) { /* * Outch... that isn't a ready signal. It's dead, Jim! */ SetEvent(hExitEvent); apr_pool_destroy(ptemp); CloseHandle(hExitEvent); CloseHandle(new_child.hproc); return -1; } if (send_listeners_to_child(ptemp, new_child.pid, new_child.in)) { /* * This error is fatal, mop up the child and move on * We toggle the child's exit event to cause this child * to quit even as it is attempting to start. */ SetEvent(hExitEvent); apr_pool_destroy(ptemp); CloseHandle(hExitEvent); CloseHandle(new_child.hproc); return -1; } apr_file_close(new_child.in); *child_exit_event = hExitEvent; *child_proc = new_child.hproc; *child_pid = new_child.pid; return 0;}/*********************************************************************** * master_main() * master_main() runs in the parent process. It creates the child * process which handles HTTP requests then waits on one of three * events: * * restart_event * ------------- * The restart event causes master_main to start a new child process and * tells the old child process to exit (by setting the child_exit_event). * The restart event is set as a result of one of the following: * 1. An apache -k restart command on the command line * 2. A command received from Windows service manager which gets * translated into an ap_signal_parent(SIGNAL_PARENT_RESTART) * call by code in service.c. * 3. The child process calling ap_signal_parent(SIGNAL_PARENT_RESTART) * as a result of hitting MaxRequestsPerChild. * * shutdown_event * -------------- * The shutdown event causes master_main to tell the child process to * exit and that the server is shutting down. The shutdown event is * set as a result of one of the following: * 1. An apache -k shutdown command on the command line * 2. A command received from Windows service manager which gets * translated into an ap_signal_parent(SIGNAL_PARENT_SHUTDOWN) * call by code in service.c. * * child process handle * -------------------- * The child process handle will be signaled if the child process * exits for any reason. In a normal running server, the signaling * of this event means that the child process has exited prematurely * due to a seg fault or other irrecoverable error. For server * robustness, master_main will restart the child process under this * condtion. * * master_main uses the child_exit_event to signal the child process * to exit. **********************************************************************/#define NUM_WAIT_HANDLES 3#define CHILD_HANDLE 0#define SHUTDOWN_HANDLE 1#define RESTART_HANDLE 2static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_event){ int rv, cld; int restart_pending; int shutdown_pending; HANDLE child_exit_event; HANDLE event_handles[NUM_WAIT_HANDLES]; DWORD child_pid; restart_pending = shutdown_pending = 0; event_handles[SHUTDOWN_HANDLE] = shutdown_event; event_handles[RESTART_HANDLE] = restart_event; /* Create a single child process */ rv = create_process(pconf, &event_handles[CHILD_HANDLE], &child_exit_event, &child_pid); if (rv < 0) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, "master_main: create child process failed. Exiting."); shutdown_pending = 1; goto die_now; } if (!strcasecmp(signal_arg, "runservice")) { mpm_service_started(); } /* Update the scoreboard. Note that there is only a single active * child at once. */ ap_scoreboard_image->parent[0].quiescing = 0; ap_scoreboard_image->parent[0].pid = child_pid; /* Wait for shutdown or restart events or for child death */ winnt_mpm_state = AP_MPMQ_RUNNING; rv = WaitForMultipleObjects(NUM_WAIT_HANDLES, (HANDLE *) event_handles, FALSE, INFINITE); cld = rv - WAIT_OBJECT_0; if (rv == WAIT_FAILED) { /* Something serious is wrong */ ap_log_error(APLOG_MARK,APLOG_CRIT, apr_get_os_error(), ap_server_conf, "master_main: WaitForMultipeObjects WAIT_FAILED -- doing server shutdown"); shutdown_pending = 1; } else if (rv == WAIT_TIMEOUT) { /* Hey, this cannot happen */ ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, "master_main: WaitForMultipeObjects with INFINITE wait exited with WAIT_TIMEOUT"); shutdown_pending = 1; } else if (cld == SHUTDOWN_HANDLE) { /* shutdown_event signalled */ shutdown_pending = 1; ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, s, "Parent: Received shutdown signal -- Shutting down the server."); if (ResetEvent(shutdown_event) == 0) { ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, "ResetEvent(shutdown_event)"); } } else if (cld == RESTART_HANDLE) { /* Received a restart event. Prepare the restart_event to be reused * then signal the child process to exit. */ restart_pending = 1; ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "Parent: Received restart signal -- Restarting the server."); if (ResetEvent(restart_event) == 0) { ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, "Parent: ResetEvent(restart_event) failed."); } if (SetEvent(child_exit_event) == 0) { ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, "Parent: SetEvent for child process %d failed.", event_handles[CHILD_HANDLE]); } /* Don't wait to verify that the child process really exits, * just move on with the restart. */ CloseHandle(event_handles[CHILD_HANDLE]); event_handles[CHILD_HANDLE] = NULL; } else { /* The child process exited prematurely due to a fatal error. */ DWORD exitcode; if (!GetExitCodeProcess(event_handles[CHILD_HANDLE], &exitcode)) { /* HUH? We did exit, didn't we? */ exitcode = APEXIT_CHILDFATAL; } if ( exitcode == APEXIT_CHILDFATAL || exitcode == APEXIT_CHILDINIT || exitcode == APEXIT_INIT) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "Parent: child process exited with status %u -- Aborting.", exitcode); } else { int i; restart_pending = 1; ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Parent: child process exited with status %u -- Restarting.", exitcode); for (i = 0; i < ap_threads_per_child; i++) { ap_update_child_status_from_indexes(0, i, SERVER_DEAD, NULL); } } CloseHandle(event_handles[CHILD_HANDLE]); event_handles[CHILD_HANDLE] = NULL; } if (restart_pending) { ++ap_my_generation; ap_scoreboard_image->global->running_generation = ap_my_generation; }die_now: if (shutdown_pending) { int timeout = 30000; /* Timeout is milliseconds */ winnt_mpm_state = AP_MPMQ_STOPPING; /* This shutdown is only marginally graceful. We will give the * child a bit of time to exit gracefully. If the time expires, * the child will be wacked. */ if (!strcasecmp(signal_arg, "runservice")) { mpm_service_stopping(); } /* Signal the child processes to exit */ if (SetEvent(child_exit_event) == 0) { ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_os_error(), ap_server_conf, "Parent: SetEvent for child process %d failed", event_handles[CHILD_HANDLE]); } if (event_handles[CHILD_HANDLE]) { rv = WaitForSingleObject(event_handles[CHILD_HANDLE], timeout); if (rv == WAIT_OBJECT_0) { ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Parent: Child process exited successfully."); CloseHandle(event_handles[CHILD_HANDLE]); event_handles[CHILD_HANDLE] = NULL; } else { ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Parent: Forcing termination of child process %d ", event_handles[CHILD_HANDLE]); TerminateProcess(event_handles[CHILD_HANDLE], 1); CloseHandle(event_handles[CHILD_HANDLE]); event_handles[CHILD_HANDLE] = NULL; } } CloseHandle(child_exit_event); return 0; /* Tell the caller we do not want to restart */ } winnt_mpm_state = AP_MPMQ_STARTING; CloseHandle(child_exit_event); return 1; /* Tell the caller we want a restart */}/* service_nt_main_fn needs to append the StartService() args * outside of our call stack and thread as the service starts... */apr_array_header_t *mpm_new_argv;/* Remember service_to_start failures to log and fail in pre_config. * Remember inst_argc and inst_argv for installing or starting the * service after we preflight the config. */AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result){ switch(query_code){ case AP_MPMQ_MAX_DAEMON_USED: *result = MAXIMUM_WAIT_OBJECTS; return APR_SUCCESS; case AP_MPMQ_IS_THREADED: *result = AP_MPMQ_STATIC; return APR_SUCCESS; case AP_MPMQ_IS_FORKED: *result = AP_MPMQ_NOT_SUPPORTED; return APR_SUCCESS; case AP_MPMQ_HARD_LIMIT_DAEMONS: *result = HARD_SERVER_LIMIT; return APR_SUCCESS; case AP_MPMQ_HARD_LIMIT_THREADS: *result = thread_limit; return APR_SUCCESS; case AP_MPMQ_MAX_THREADS: *result = ap_threads_per_child; return APR_SUCCESS; case AP_MPMQ_MIN_SPARE_DAEMONS: *result = 0; return APR_SUCCESS; case AP_MPMQ_MIN_SPARE_THREADS: *result = 0; return APR_SUCCESS; case AP_MPMQ_MAX_SPARE_DAEMONS: *result = 0; return APR_SUCCESS; case AP_MPMQ_MAX_SPARE_THREADS: *result = 0; return APR_SUCCESS; case AP_MPMQ_MAX_REQUESTS_DAEMON: *result = ap_max_requests_per_child; return APR_SUCCESS; case AP_MPMQ_MAX_DAEMONS: *result = 0; return APR_SUCCESS; case AP_MPMQ_MPM_STATE: *result = winnt_mpm_state; return APR_SUCCESS; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -