📄 mpm_winnt.c
字号:
}
/* Create the child_ready_event */
waitlist[waitlist_ready] = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!waitlist[waitlist_ready]) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
"Parent: Could not create ready event for child process");
apr_pool_destroy (ptemp);
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 2
static 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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -