⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpm_winnt.c

📁 Apache 2.0.63 is the current stable version of the 2.0 series, and is recommended over any previous
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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),

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -