mpm_winnt.c revision 53bb9198689cfcc08182c9bb27005368bcba42a2
f3ec420152ca921e4c1ce77782f51b53f659018dnd/* ====================================================================
f3ec420152ca921e4c1ce77782f51b53f659018dnd * The Apache Software License, Version 1.1
f3ec420152ca921e4c1ce77782f51b53f659018dnd * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
f3ec420152ca921e4c1ce77782f51b53f659018dnd * reserved.
f3ec420152ca921e4c1ce77782f51b53f659018dnd * Redistribution and use in source and binary forms, with or without
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc * modification, are permitted provided that the following conditions
f3ec420152ca921e4c1ce77782f51b53f659018dnd * are met:
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 1. Redistributions of source code must retain the above copyright
2e545ce2450a9953665f701bb05350f0d3f26275nd * notice, this list of conditions and the following disclaimer.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 2. Redistributions in binary form must reproduce the above copyright
f3ec420152ca921e4c1ce77782f51b53f659018dnd * notice, this list of conditions and the following disclaimer in
f3ec420152ca921e4c1ce77782f51b53f659018dnd * the documentation and/or other materials provided with the
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen * distribution.
f3ec420152ca921e4c1ce77782f51b53f659018dnd * 3. The end-user documentation included with the redistribution,
f3ec420152ca921e4c1ce77782f51b53f659018dnd * if any, must include the following acknowledgment:
f3ec420152ca921e4c1ce77782f51b53f659018dnd * "This product includes software developed by the
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * Apache Software Foundation (http://www.apache.org/)."
f3ec420152ca921e4c1ce77782f51b53f659018dnd * Alternately, this acknowledgment may appear in the software itself,
f3ec420152ca921e4c1ce77782f51b53f659018dnd * if and wherever such third-party acknowledgments normally appear.
f3ec420152ca921e4c1ce77782f51b53f659018dnd * 4. The names "Apache" and "Apache Software Foundation" must
f3ec420152ca921e4c1ce77782f51b53f659018dnd * not be used to endorse or promote products derived from this
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung * software without prior written permission. For written
f3ec420152ca921e4c1ce77782f51b53f659018dnd * permission, please contact apache@apache.org.
f3ec420152ca921e4c1ce77782f51b53f659018dnd * 5. Products derived from this software may not be called "Apache",
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * nor may "Apache" appear in their name, without prior written
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * permission of the Apache Software Foundation.
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
f3ec420152ca921e4c1ce77782f51b53f659018dnd * SUCH DAMAGE.
f3ec420152ca921e4c1ce77782f51b53f659018dnd * ====================================================================
f3ec420152ca921e4c1ce77782f51b53f659018dnd * This software consists of voluntary contributions made by many
f3ec420152ca921e4c1ce77782f51b53f659018dnd * individuals on behalf of the Apache Software Foundation. For more
f3ec420152ca921e4c1ce77782f51b53f659018dnd * information on the Apache Software Foundation, please see
f3ec420152ca921e4c1ce77782f51b53f659018dnd * Portions of this software are based upon public domain software
f3ec420152ca921e4c1ce77782f51b53f659018dnd * originally written at the National Center for Supercomputing Applications,
f3ec420152ca921e4c1ce77782f51b53f659018dnd * University of Illinois, Urbana-Champaign.
f3ec420152ca921e4c1ce77782f51b53f659018dnd * Definitions of WINNT MPM specific config globals
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic int workers_may_exit = 0;
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic int shutdown_in_progress = 0;
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic unsigned int g_blocked_threads = 0;
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic int max_requests_per_child = 0;
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic HANDLE shutdown_event; /* used to signal shutdown to parent */
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic HANDLE restart_event; /* used to signal a restart to parent */
f3ec420152ca921e4c1ce77782f51b53f659018dnd#define MAX_SIGNAL_NAME 30 /* Long enough for apPID_shutdown, where PID is an int */
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic int num_listenfds = 0;
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic int one_process = 0;
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic char const* signal_arg;
f3ec420152ca921e4c1ce77782f51b53f659018dnd/* ap_get_max_daemons and ap_my_generation are used by the scoreboard
f3ec420152ca921e4c1ce77782f51b53f659018dndap_generation_t volatile ap_my_generation=0; /* Used by the scoreboard */
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen/* This is the helper code to resolve late bound entry points
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * missing from one or more releases of the Win32 API...
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * but it sure would be nice if we didn't duplicate this code
f3ec420152ca921e4c1ce77782f51b53f659018dnd * from the APR ;-)
f3ec420152ca921e4c1ce77782f51b53f659018dndFARPROC ap_load_dll_func(ap_dlltoken_e fnLib, char* fnName, int ordinal)
f3ec420152ca921e4c1ce77782f51b53f659018dnd return GetProcAddress(lateDllHandle[fnLib], (char *) ordinal);
f3ec420152ca921e4c1ce77782f51b53f659018dnd/* A bunch or routines from os/win32/multithread.c that need to be merged into APR
f3ec420152ca921e4c1ce77782f51b53f659018dnd * or thrown out entirely...
f3ec420152ca921e4c1ce77782f51b53f659018dnd/* To share the semaphores with other processes, we need a NULL ACL
f3ec420152ca921e4c1ce77782f51b53f659018dnd * Code from MS KB Q106387
f3ec420152ca921e4c1ce77782f51b53f659018dnd sa = (PSECURITY_ATTRIBUTES) LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES));
f3ec420152ca921e4c1ce77782f51b53f659018dnd if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)
f3ec420152ca921e4c1ce77782f51b53f659018dnd if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE)
f3ec420152ca921e4c1ce77782f51b53f659018dnd LocalFree( ((PSECURITY_ATTRIBUTES)sa)->lpSecurityDescriptor);
f3ec420152ca921e4c1ce77782f51b53f659018dnd * The Win32 call WaitForMultipleObjects will only allow you to wait for
f3ec420152ca921e4c1ce77782f51b53f659018dnd * a maximum of MAXIMUM_WAIT_OBJECTS (current 64). Since the threading
f3ec420152ca921e4c1ce77782f51b53f659018dnd * model in the multithreaded version of apache wants to use this call,
f3ec420152ca921e4c1ce77782f51b53f659018dnd * we are restricted to a maximum of 64 threads. This is a simplistic
f3ec420152ca921e4c1ce77782f51b53f659018dnd * routine that will increase this size.
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic DWORD wait_for_many_objects(DWORD nCount, CONST HANDLE *lpHandles,
f3ec420152ca921e4c1ce77782f51b53f659018dnd for (dwIndex = 0; dwIndex * MAXIMUM_WAIT_OBJECTS < nCount; dwIndex++) {
f3ec420152ca921e4c1ce77782f51b53f659018dnd min(MAXIMUM_WAIT_OBJECTS, nCount - (dwIndex * MAXIMUM_WAIT_OBJECTS)),
f3ec420152ca921e4c1ce77782f51b53f659018dnd } while((time(NULL) < tStopTime) && (dwRet == WAIT_TIMEOUT));
f3ec420152ca921e4c1ce77782f51b53f659018dnd * Signalling Apache on NT.
f3ec420152ca921e4c1ce77782f51b53f659018dnd * Under Unix, Apache can be told to shutdown or restart by sending various
f3ec420152ca921e4c1ce77782f51b53f659018dnd * signals (HUP, USR, TERM). On NT we don't have easy access to signals, so
f3ec420152ca921e4c1ce77782f51b53f659018dnd * we use "events" instead. The parent apache process goes into a loop
f3ec420152ca921e4c1ce77782f51b53f659018dnd * where it waits forever for a set of events. Two of those events are
f3ec420152ca921e4c1ce77782f51b53f659018dnd * apPID_shutdown
f3ec420152ca921e4c1ce77782f51b53f659018dnd * apPID_restart
f3ec420152ca921e4c1ce77782f51b53f659018dnd * (where PID is the PID of the apache parent process). When one of these
f3ec420152ca921e4c1ce77782f51b53f659018dnd * is signalled, the Apache parent performs the appropriate action. The events
f3ec420152ca921e4c1ce77782f51b53f659018dnd * can become signalled through internal Apache methods (e.g. if the child
f3ec420152ca921e4c1ce77782f51b53f659018dnd * finds a fatal error and needs to kill its parent), via the service
f3ec420152ca921e4c1ce77782f51b53f659018dnd * control manager (the control thread will signal the shutdown event when
f3ec420152ca921e4c1ce77782f51b53f659018dnd * requested to stop the Apache service), from the -k Apache command line,
f3ec420152ca921e4c1ce77782f51b53f659018dnd * or from any external program which finds the Apache PID from the
f3ec420152ca921e4c1ce77782f51b53f659018dnd * httpd.pid file.
f3ec420152ca921e4c1ce77782f51b53f659018dnd * The signal_parent() function, below, is used to signal one of these events.
f3ec420152ca921e4c1ce77782f51b53f659018dnd * It can be called by any child or parent process, since it does not
f3ec420152ca921e4c1ce77782f51b53f659018dnd * rely on global variables.
f3ec420152ca921e4c1ce77782f51b53f659018dnd * On entry, type gives the event to signal. 0 means shutdown, 1 means
f3ec420152ca921e4c1ce77782f51b53f659018dnd * graceful restart.
723b4be7951b76cd58116426912adacf55bf96ednilgun /* after updating the shutdown_pending or restart flags, we need
723b4be7951b76cd58116426912adacf55bf96ednilgun * to wake up the parent process so it can see the changes. The
723b4be7951b76cd58116426912adacf55bf96ednilgun * parent will normally be waiting for either a child process
723b4be7951b76cd58116426912adacf55bf96ednilgun * to die, or for a signal on the "spache-signal" event. So set the
723b4be7951b76cd58116426912adacf55bf96ednilgun * "apache-signal" event here.
f3ec420152ca921e4c1ce77782f51b53f659018dnd default: return;
f3ec420152ca921e4c1ce77782f51b53f659018dnd /* Um, problem, can't signal the parent, which means we can't
f3ec420152ca921e4c1ce77782f51b53f659018dnd * signal ourselves to die. Ignore for now...
f3ec420152ca921e4c1ce77782f51b53f659018dnd ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), server_conf,
f3ec420152ca921e4c1ce77782f51b53f659018dnd if (SetEvent(e) == 0) {
f3ec420152ca921e4c1ce77782f51b53f659018dnd /* Same problem as above */
f3ec420152ca921e4c1ce77782f51b53f659018dnd ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), server_conf,
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic int volatile is_graceful = 0;
f3ec420152ca921e4c1ce77782f51b53f659018dnd * Initialise the signal names, in the global variables signal_name_prefix,
f3ec420152ca921e4c1ce77782f51b53f659018dnd * signal_restart_name and signal_shutdown_name.
f3ec420152ca921e4c1ce77782f51b53f659018dnd apr_snprintf(signal_name_prefix, sizeof(signal_name_prefix), prefix);
f3ec420152ca921e4c1ce77782f51b53f659018dnd apr_snprintf(signal_shutdown_name, sizeof(signal_shutdown_name),
f3ec420152ca921e4c1ce77782f51b53f659018dnd apr_snprintf(signal_restart_name, sizeof(signal_restart_name),
f3ec420152ca921e4c1ce77782f51b53f659018dnd * Routines that deal with sockets, some are WIN32 specific...
f3ec420152ca921e4c1ce77782f51b53f659018dndstatic void sock_disable_nagle(int s)
d23070a273525fb69f21f5426d31a32157dad337nilgun /* The Nagle algorithm says that we should delay sending partial
d23070a273525fb69f21f5426d31a32157dad337nilgun * packets in hopes of getting more data. We don't want to do
f3ec420152ca921e4c1ce77782f51b53f659018dnd * this; we are not telnet. There are bad interactions between
f3ec420152ca921e4c1ce77782f51b53f659018dnd * persistent connections and Nagle's algorithm that have very severe
f3ec420152ca921e4c1ce77782f51b53f659018dnd * performance penalties. (Failing to disable Nagle is not much of a
d23070a273525fb69f21f5426d31a32157dad337nilgun * problem with simple HTTP.)
f3ec420152ca921e4c1ce77782f51b53f659018dnd * In spite of these problems, failure here is not a shooting offense.
f3ec420152ca921e4c1ce77782f51b53f659018dnd if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &just_say_no,
f3ec420152ca921e4c1ce77782f51b53f659018dnd sizeof(int)) < 0) {
f3ec420152ca921e4c1ce77782f51b53f659018dnd ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, server_conf,
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen "setsockopt: (TCP_NODELAY)");
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen * Routines to deal with managing the list of listening sockets.
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowenstatic apr_inline ap_listen_rec *find_ready_listener(fd_set * main_fds)
f3ec420152ca921e4c1ce77782f51b53f659018dnd /* Setup the listeners */
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen if (listenmaxfd == INVALID_SOCKET || nsd > listenmaxfd) {
f3ec420152ca921e4c1ce77782f51b53f659018dnd /* Setup the listeners */
f3ec420152ca921e4c1ce77782f51b53f659018dnd /* Set up a default listener if necessary */
f3ec420152ca921e4c1ce77782f51b53f659018dnd lr = apr_palloc(s->process->pool, sizeof(ap_listen_rec));
f3ec420152ca921e4c1ce77782f51b53f659018dnd /* Open the pipe to the parent process to receive the inherited socket
f3ec420152ca921e4c1ce77782f51b53f659018dnd * data. The sockets have been set to listening in the parent process.
f3ec420152ca921e4c1ce77782f51b53f659018dnd if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO),
d1636bdc2e674b84ee46f534b51be18ecac6bef5rbowen ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf,
f3ec420152ca921e4c1ce77782f51b53f659018dnd "setup_inherited_listeners: Unable to read socket data from parent");
f3ec420152ca921e4c1ce77782f51b53f659018dnd ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, server_conf,
f3ec420152ca921e4c1ce77782f51b53f659018dnd "Child %d: setup_inherited_listener() read = %d bytes of WSAProtocolInfo.", my_pid);
f3ec420152ca921e4c1ce77782f51b53f659018dnd nsd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
f3ec420152ca921e4c1ce77782f51b53f659018dnd ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), server_conf,
f3ec420152ca921e4c1ce77782f51b53f659018dnd "Child %d: setup_inherited_listeners(), WSASocket failed to open the inherited socket.", my_pid);
f3ec420152ca921e4c1ce77782f51b53f659018dnd if (nsd >= 0) {
f3ec420152ca921e4c1ce77782f51b53f659018dnd if (listenmaxfd == INVALID_SOCKET || nsd > listenmaxfd) {
0d0ba3a410038e179b695446bb149cce6264e0abnd /* Now, read the AcceptExCompPort from the parent */
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh ReadFile(pipe, &AcceptExCompPort, sizeof(AcceptExCompPort), &BytesRead, (LPOVERLAPPED) NULL);
07dc96d063d49299da433f84b5c5681da9bbdf68rbowen /* Associate the open listeners with the completion port.
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen * Bypass the operation for Windows 95/98
int nsd;
* threads. add_job/remove_job are not used by the NT/2000 specific
typedef struct joblist_s {
int sock;
} joblist;
typedef struct globals_s {
int jobcount;
} globals;
static int remove_job(void)
int sock;
return (sock);
int requests_this_child = 0;
int csd;
int count_select_errors = 0;
int rc;
int clen;
while (!shutdown_in_progress) {
if (csd < 0) {
int len;
if (!context) {
return NULL;
return NULL;
return context;
int rc;
if (!rc) {
int lasterror;
if (!context) {
sizeof(nsd))) {
int rc, i;
return rc;
return APR_SUCCESS;
int requests_this_child = 0;
int rc;
if (shutdown_in_progress) {
my_pid);
if (workers_may_exit) {
return NULL;
if (!rc) {
my_pid);
if (pol) {
my_pid);
if (CompKey != 0) {
return NULL;
if (!shutdown_in_progress) {
return context;
conn_rec *c;
if (!context)
if (!disconnected) {
(*thread_cnt)--;
static void create_listeners()
static void child_main()
char* exit_event_name;
int tid;
int rv;
int cld;
if (one_process) {
exit(0);
for (i = 0; i < nthreads; i++) {
(void *) i, 0, &tid);
(void *) i, 0, &tid);
else if (cld == 0) {
for (i = 0; i < nthreads; i++) {
while (g_blocked_threads > 0) {
for (i=g_blocked_threads; i > 0; i--) {
while (nthreads) {
for (i = 0; i < nthreads; i++) {
int handle = 0;
(*processes)--;
int rv;
char *pCommand;
char *pEnvVar;
char *pEnvBlock;
int iEnvBlockLen;
* C:/apache/bin/apache.exe -f ap_server_confname
} else if (rv == 0) {
while (_environ[i]) {
while (_environ[i]) {
NULL,
if (!kill_event) {
(*processes)++;
int nsd;
WriteFile(hPipeWrite, &hDupedCompPort, (DWORD) sizeof(hDupedCompPort), &BytesWritten, (LPOVERLAPPED) NULL);
int child_num = 0;
int restart_pending = 0;
int shutdown_pending = 0;
setup_listeners(s);
while (remaining_children_to_start--) {
¤t_live_processes) < 0) {
goto die_now;
for (i = 0; i < children_to_kill; i++) {
* Consider, however, that if the user makes httpd.conf invalid, we want to die before
if (shutdown_pending)
for (i = 0; i < current_live_processes; i++) {
for (i = 0; i < current_live_processes; i++) {
static int inst_argc;
static const char * const *inst_argv;
char *def_server_root;
const char *optarg;
int fixed_args;
char *pid;
if (pid)
if (optarg) {
if (!signal_arg)
running_as_service = 0;
else if (running_as_service)
* in these cases we -don't- care if httpd.conf has config errors!
exit(0);
static void winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec* server)
static int restart_num = 0;
* is a valid conf\httpd.conf environment to start.
NULL,
if (!shutdown_event) {
if (!restart_event) {
server_conf = s;
child_main();
if (!restart) {
return err;
return NULL;
return err;
return NULL;
return err;
return NULL;
const char *fname;
return err;
return NULL;
const char *value)
return NULL;
{ NULL }