📄 mpm_winnt.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#ifdef WIN32#define CORE_PRIVATE #include "httpd.h" #include "http_main.h" #include "http_log.h" #include "http_config.h" /* for read_config */ #include "http_core.h" /* for get_remote_host */ #include "http_connection.h"#include "apr_portable.h"#include "apr_thread_proc.h"#include "apr_getopt.h"#include "apr_strings.h"#include "apr_lib.h"#include "apr_shm.h"#include "apr_thread_mutex.h"#include "ap_mpm.h"#include "ap_config.h"#include "ap_listen.h"#include "mpm_default.h"#include "mpm_winnt.h"#include "mpm_common.h"#include <malloc.h>#include "apr_atomic.h"/* scoreboard.c does the heavy lifting; all we do is create the child * score by moving a handle down the pipe into the child's stdin. */extern apr_shm_t *ap_scoreboard_shm;server_rec *ap_server_conf;/* Definitions of WINNT MPM specific config globals */static HANDLE shutdown_event; /* used to signal the parent to shutdown */static HANDLE restart_event; /* used to signal the parent to restart */static char ap_coredump_dir[MAX_STRING_LEN];static int one_process = 0;static char const* signal_arg = NULL;OSVERSIONINFO osver; /* VER_PLATFORM_WIN32_NT */static DWORD parent_pid;DWORD my_pid;int ap_threads_per_child = 0;int use_acceptex = 1;static int thread_limit = DEFAULT_THREAD_LIMIT;static int first_thread_limit = 0;static int changed_limit_at_restart;int winnt_mpm_state = AP_MPMQ_STARTING;/* ap_my_generation are used by the scoreboard code */ap_generation_t volatile ap_my_generation=0;/* shared by service.c as global, although * perhaps it should be private. */apr_pool_t *pconf;/* definitions from child.c */void child_main(apr_pool_t *pconf);/* used by parent to signal the child to start and exit * NOTE: these are not sophisticated enough for multiple children * so they ultimately should not be shared with child.c */extern apr_proc_mutex_t *start_mutex;extern HANDLE exit_event; /* Only one of these, the pipe from our parent, ment only for * one child worker's consumption (not to be inherited!) * XXX: decorate this name for the trunk branch, was left simplified * only to make the 2.2 patch trivial to read. */static HANDLE pipe;/* Stub functions until this MPM supports the connection status API */AP_DECLARE(void) ap_update_connection_status(long conn_id, const char *key, \ const char *value){ /* NOP */}AP_DECLARE(void) ap_reset_connection_status(long conn_id){ /* NOP */}AP_DECLARE(apr_array_header_t *) ap_get_status_table(apr_pool_t *p){ /* NOP */ return NULL;}/* * Command processors */static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, char *arg) { const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { return err; } ap_threads_per_child = atoi(arg); if (ap_threads_per_child > thread_limit) { ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "WARNING: ThreadsPerChild of %d exceeds ThreadLimit " "value of %d threads,", ap_threads_per_child, thread_limit); ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, " lowering ThreadsPerChild to %d. To increase, please" " see the", thread_limit); ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, " ThreadLimit directive."); ap_threads_per_child = thread_limit; } else if (ap_threads_per_child < 1) { ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "WARNING: Require ThreadsPerChild > 0, setting to 1"); ap_threads_per_child = 1; } return NULL;}static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg) { int tmp_thread_limit; const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { return err; } tmp_thread_limit = atoi(arg); /* you cannot change ThreadLimit across a restart; ignore * any such attempts */ if (first_thread_limit && tmp_thread_limit != thread_limit) { /* how do we log a message? the error log is a bit bucket at this * point; we'll just have to set a flag so that ap_mpm_run() * logs a warning later */ changed_limit_at_restart = 1; return NULL; } thread_limit = tmp_thread_limit; if (thread_limit > MAX_THREAD_LIMIT) { ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "WARNING: ThreadLimit of %d exceeds compile time limit " "of %d threads,", thread_limit, MAX_THREAD_LIMIT); ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT); thread_limit = MAX_THREAD_LIMIT; } else if (thread_limit < 1) { ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "WARNING: Require ThreadLimit > 0, setting to 1"); thread_limit = 1; } return NULL;}static const char *set_disable_acceptex(cmd_parms *cmd, void *dummy, char *arg) { const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { return err; } if (use_acceptex) { use_acceptex = 0; ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "Disabled use of AcceptEx() WinSock2 API"); } return NULL;}static const command_rec winnt_cmds[] = {LISTEN_COMMANDS,AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, "Number of threads each child creates" ),AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF, "Maximum worker threads in a server for this run of Apache"),AP_INIT_NO_ARGS("Win32DisableAcceptEx", set_disable_acceptex, NULL, RSRC_CONF, "Disable use of the high performance AcceptEx WinSock2 API to work around buggy VPN or Firewall software"),{ NULL }};/* * Signalling Apache on NT. * * Under Unix, Apache can be told to shutdown or restart by sending various * signals (HUP, USR, TERM). On NT we don't have easy access to signals, so * we use "events" instead. The parent apache process goes into a loop * where it waits forever for a set of events. Two of those events are * called * * apPID_shutdown * apPID_restart * * (where PID is the PID of the apache parent process). When one of these * is signalled, the Apache parent performs the appropriate action. The events * can become signalled through internal Apache methods (e.g. if the child * finds a fatal error and needs to kill its parent), via the service * control manager (the control thread will signal the shutdown event when * requested to stop the Apache service), from the -k Apache command line, * or from any external program which finds the Apache PID from the * httpd.pid file. * * The signal_parent() function, below, is used to signal one of these events. * It can be called by any child or parent process, since it does not * rely on global variables. * * On entry, type gives the event to signal. 0 means shutdown, 1 means * graceful restart. *//* * Initialise the signal names, in the global variables signal_name_prefix, * signal_restart_name and signal_shutdown_name. */#define MAX_SIGNAL_NAME 30 /* Long enough for apPID_shutdown, where PID is an int */char signal_name_prefix[MAX_SIGNAL_NAME];char signal_restart_name[MAX_SIGNAL_NAME]; char signal_shutdown_name[MAX_SIGNAL_NAME];void setup_signal_names(char *prefix){ apr_snprintf(signal_name_prefix, sizeof(signal_name_prefix), prefix); apr_snprintf(signal_shutdown_name, sizeof(signal_shutdown_name), "%s_shutdown", signal_name_prefix); apr_snprintf(signal_restart_name, sizeof(signal_restart_name), "%s_restart", signal_name_prefix); }int volatile is_graceful = 0;AP_DECLARE(int) ap_graceful_stop_signalled(void){ return is_graceful;}AP_DECLARE(void) ap_signal_parent(ap_signal_parent_e type){ HANDLE e; char *signal_name; if (parent_pid == my_pid) { switch(type) { case SIGNAL_PARENT_SHUTDOWN: { SetEvent(shutdown_event); break; } /* This MPM supports only graceful restarts right now */ case SIGNAL_PARENT_RESTART: case SIGNAL_PARENT_RESTART_GRACEFUL: { is_graceful = 1; SetEvent(restart_event); break; } } return; } switch(type) { case SIGNAL_PARENT_SHUTDOWN: { signal_name = signal_shutdown_name; break; } /* This MPM supports only graceful restarts right now */ case SIGNAL_PARENT_RESTART: case SIGNAL_PARENT_RESTART_GRACEFUL: { signal_name = signal_restart_name; is_graceful = 1; break; } default: return; } e = OpenEvent(EVENT_MODIFY_STATE, FALSE, signal_name); if (!e) { /* Um, problem, can't signal the parent, which means we can't * signal ourselves to die. Ignore for now... */ ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), ap_server_conf, "OpenEvent on %s event", signal_name); return; } if (SetEvent(e) == 0) { /* Same problem as above */ ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), ap_server_conf, "SetEvent on %s event", signal_name); CloseHandle(e); return; } CloseHandle(e);}/* * Passed the following handles [in sync with send_handles_to_child()] * * ready event [signal the parent immediately, then close] * exit event [save to poll later] * start mutex [signal from the parent to begin accept()] * scoreboard shm handle [to recreate the ap_scoreboard] */void get_handles_from_parent(server_rec *s, HANDLE *child_exit_event, apr_proc_mutex_t **child_start_mutex, apr_shm_t **scoreboard_shm){ HANDLE hScore; HANDLE ready_event; HANDLE os_start; DWORD BytesRead; void *sb_shared; apr_status_t rv; /* *** We now do this was back in winnt_rewrite_args * pipe = GetStdHandle(STD_INPUT_HANDLE); */ if (!ReadFile(pipe, &ready_event, sizeof(HANDLE), &BytesRead, (LPOVERLAPPED) NULL) || (BytesRead != sizeof(HANDLE))) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, "Child %d: Unable to retrieve the ready event from the parent", my_pid);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -