]> granicus.if.org Git - apache/blobdiff - server/mpm/winnt/mpm_winnt.c
apr_proc_mutex.h is called for by this very header
[apache] / server / mpm / winnt / mpm_winnt.c
index f82c36dbb81166317ec7662f5ec0b912579c7bdd..45ac052b83779009a10ce3a7f4535c347c7d681e 100644 (file)
@@ -1,69 +1,26 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
+/* 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
  *
- * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
- * reserved.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- *    if any, must include the following acknowledgment:
- *       "This product includes software developed by the
- *        Apache Software Foundation (http://www.apache.org/)."
- *    Alternately, this acknowledgment may appear in the software itself,
- *    if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Apache" and "Apache Software Foundation" must
- *    not be used to endorse or promote products derived from this
- *    software without prior written permission. For written
- *    permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- *    nor may "Apache" appear in their name, without prior written
- *    permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
+ * 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 "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"
  * 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;
+
+/* ap_my_generation are used by the scoreboard code */
+ap_generation_t volatile ap_my_generation=0;
 
 /* 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 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];
 
@@ -99,35 +58,40 @@ static char const* signal_arg = NULL;
 
 OSVERSIONINFO osver; /* VER_PLATFORM_WIN32_NT */
 
+/* set by child_main to STACK_SIZE_PARAM_IS_A_RESERVATION for NT >= 5.1 (XP/2003) */
+DWORD stack_res_flag;
+
 static DWORD parent_pid;
 DWORD my_pid;
 
-int windows_sockets_workaround = 0;
+/* used by parent to signal the child to start and exit */
+apr_proc_mutex_t *start_mutex;
+HANDLE exit_event;
+
 int ap_threads_per_child = 0;
-static int thread_limit = DEFAULT_THREAD_LIMIT;
+static int thread_limit = 0;
 static int first_thread_limit = 0;
-static int changed_limit_at_restart;
-
-/* ap_my_generation are used by the scoreboard code */
-ap_generation_t volatile ap_my_generation=0;
-
+int winnt_mpm_state = AP_MPMQ_STARTING;
 
-/* shared by service.c as global, although 
+/* shared by service.c as global, although
  * perhaps it should be private.
  */
 apr_pool_t *pconf;
 
+/* on several occasions we don't have the global server context
+ * although it's needed for logging, etc.
+ */
+server_rec *ap_server_conf;
 
 /* 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
+/* 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.
  */
-extern apr_proc_mutex_t *start_mutex;
-extern HANDLE exit_event;  
-
+static HANDLE pipe;
 
 /* Stub functions until this MPM supports the connection status API */
 
@@ -148,11 +112,11 @@ AP_DECLARE(apr_array_header_t *) ap_get_status_table(apr_pool_t *p)
     return NULL;
 }
 
-/* 
- * Command processors 
+/*
+ * Command processors
  */
 
-static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, char *arg) 
+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) {
@@ -160,82 +124,18 @@ static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, char *arg
     }
 
     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) 
+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;
-    }
+    thread_limit = atoi(arg);
     return NULL;
 }
-static const char *set_sockets_workaround (cmd_parms *cmd, void *dummy, char *arg) 
-{
-    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
-    if (err != NULL) {
-        return err;
-    }
-
-    windows_sockets_workaround = 0;
-    if (!strcasecmp(arg, "on")) {
-        windows_sockets_workaround = 1;
-    }
-    else if (strcasecmp(arg, "off")) {
-        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
-                         "WARNING: setting WindowsSocketsWorkaround to off");
-    }
-    return NULL;
-}
-
 
 static const command_rec winnt_cmds[] = {
 LISTEN_COMMANDS,
@@ -243,9 +143,6 @@ 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_TAKE1("WindowsSocketsWorkaround", set_sockets_workaround, NULL, RSRC_CONF,
-  "Set \"on\" to work around buggy Winsock provider implementations of certain VPN or Firewall software"),
-
 { NULL }
 };
 
@@ -275,90 +172,81 @@ AP_INIT_TAKE1("WindowsSocketsWorkaround", set_sockets_workaround, NULL, RSRC_CON
  * 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 
+ * 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, 
+ * 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_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;
+    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);
 }
 
 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: 
+           case SIGNAL_PARENT_SHUTDOWN:
            {
-               SetEvent(shutdown_event); 
+               SetEvent(shutdown_event);
                break;
            }
            /* This MPM supports only graceful restarts right now */
-           case SIGNAL_PARENT_RESTART: 
+           case SIGNAL_PARENT_RESTART:
            case SIGNAL_PARENT_RESTART_GRACEFUL:
            {
-               is_graceful = 1;
-               SetEvent(restart_event); 
+               SetEvent(restart_event);
                break;
            }
         }
-       return;
+        return;
     }
 
     switch(type) {
-       case SIGNAL_PARENT_SHUTDOWN: 
+       case SIGNAL_PARENT_SHUTDOWN:
        {
-           signal_name = signal_shutdown_name; 
+           signal_name = signal_shutdown_name;
            break;
        }
        /* This MPM supports only graceful restarts right now */
-       case SIGNAL_PARENT_RESTART: 
+       case SIGNAL_PARENT_RESTART:
        case SIGNAL_PARENT_RESTART_GRACEFUL:
        {
-           signal_name = signal_restart_name;     
-           is_graceful = 1;
+           signal_name = signal_restart_name;
            break;
        }
-       default: 
+       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,
+        /* 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;
+        return;
     }
     if (SetEvent(e) == 0) {
-       /* Same problem as above */
-       ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), ap_server_conf,
+        /* 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);
+        return;
     }
     CloseHandle(e);
 }
@@ -376,15 +264,16 @@ 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 pipe;
     HANDLE hScore;
     HANDLE ready_event;
     HANDLE os_start;
     DWORD BytesRead;
     void *sb_shared;
     apr_status_t rv;
-    
-    pipe = GetStdHandle(STD_INPUT_HANDLE);
+
+    /* *** 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))) {
@@ -427,7 +316,7 @@ void get_handles_from_parent(server_rec *s, HANDLE *child_exit_event,
         exit(APEXIT_CHILDINIT);
     }
     *scoreboard_shm = NULL;
-    if ((rv = apr_os_shm_put(scoreboard_shm, &hScore, s->process->pool)) 
+    if ((rv = apr_os_shm_put(scoreboard_shm, &hScore, s->process->pool))
             != APR_SUCCESS) {
         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
                      "Child %d: Unable to access the scoreboard from the parent", my_pid);
@@ -436,7 +325,7 @@ void get_handles_from_parent(server_rec *s, HANDLE *child_exit_event,
 
     rv = ap_reopen_scoreboard(s->process->pool, scoreboard_shm, 1);
     if (rv || !(sb_shared = apr_shm_baseaddr_get(*scoreboard_shm))) {
-       ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, 
+        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
                      "Child %d: Unable to reopen the scoreboard from the parent", my_pid);
         exit(APEXIT_CHILDINIT);
     }
@@ -450,12 +339,12 @@ void get_handles_from_parent(server_rec *s, HANDLE *child_exit_event,
 }
 
 
-static int send_handles_to_child(apr_pool_t *p, 
+static int send_handles_to_child(apr_pool_t *p,
                                  HANDLE child_ready_event,
-                                 HANDLE child_exit_event, 
+                                 HANDLE child_exit_event,
                                  apr_proc_mutex_t *child_start_mutex,
                                  apr_shm_t *scoreboard_shm,
-                                 HANDLE hProcess, 
+                                 HANDLE hProcess,
                                  apr_file_t *child_in)
 {
     apr_status_t rv;
@@ -463,7 +352,7 @@ static int send_handles_to_child(apr_pool_t *p,
     HANDLE hDup;
     HANDLE os_start;
     HANDLE hScore;
-    DWORD BytesWritten;
+    apr_size_t BytesWritten;
 
     if (!DuplicateHandle(hCurrentProcess, child_ready_event, hProcess, &hDup,
         EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0)) {
@@ -530,7 +419,7 @@ static int send_handles_to_child(apr_pool_t *p,
 }
 
 
-/* 
+/*
  * get_listeners_from_parent()
  * The listen sockets are opened in the parent. This function, which runs
  * exclusively in the child process, receives them from the parent and
@@ -539,11 +428,12 @@ static int send_handles_to_child(apr_pool_t *p,
 void get_listeners_from_parent(server_rec *s)
 {
     WSAPROTOCOL_INFO WSAProtocolInfo;
-    HANDLE pipe;
     ap_listen_rec *lr;
     DWORD BytesRead;
     int lcnt = 0;
     SOCKET nsd;
+    HANDLE hProcess = GetCurrentProcess();
+    HANDLE dup;
 
     /* Set up a default listener if necessary */
     if (ap_listeners == NULL) {
@@ -556,16 +446,18 @@ void get_listeners_from_parent(server_rec *s)
 
     /* Open the pipe to the parent process to receive the inherited socket
      * data. The sockets have been set to listening in the parent process.
+     *
+     * *** We now do this was back in winnt_rewrite_args
+     * pipe = GetStdHandle(STD_INPUT_HANDLE);
      */
-    pipe = GetStdHandle(STD_INPUT_HANDLE);
-
     for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) {
-        if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO), 
+        if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO),
                       &BytesRead, (LPOVERLAPPED) NULL)) {
             ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
                          "setup_inherited_listeners: Unable to read socket data from parent");
             exit(APEXIT_CHILDINIT);
         }
+
         nsd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
                         &WSAProtocolInfo, 0, 0);
         if (nsd == INVALID_SOCKET) {
@@ -574,30 +466,12 @@ void get_listeners_from_parent(server_rec *s)
             exit(APEXIT_CHILDINIT);
         }
 
-        if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
-            HANDLE hProcess = GetCurrentProcess();
-            HANDLE dup;
-            if (DuplicateHandle(hProcess, (HANDLE) nsd, hProcess, &dup, 
-                                0, FALSE, DUPLICATE_SAME_ACCESS)) {
-                closesocket(nsd);
-                nsd = (SOCKET) dup;
-            }
-        }
-        else {
-            /* A different approach.  Many users report errors such as 
-             * (32538)An operation was attempted on something that is not 
-             * a socket.  : Parent: WSADuplicateSocket failed...
-             *
-             * This appears that the duplicated handle is no longer recognized
-             * as a socket handle.  SetHandleInformation should overcome that
-             * problem by not altering the handle identifier.  But this won't
-             * work on 9x - it's unsupported.
-             */
-            if (!SetHandleInformation((HANDLE)nsd, HANDLE_FLAG_INHERIT, 0)) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), ap_server_conf,
-                             "set_listeners_noninheritable: SetHandleInformation failed.");
-            }
+        if (DuplicateHandle(hProcess, (HANDLE) nsd, hProcess, &dup,
+                            0, FALSE, DUPLICATE_SAME_ACCESS)) {
+            closesocket(nsd);
+            nsd = (SOCKET) dup;
         }
+
         apr_os_sock_put(&lr->sd, &nsd, s->process->pool);
     }
 
@@ -606,25 +480,25 @@ void get_listeners_from_parent(server_rec *s)
 }
 
 
-static int send_listeners_to_child(apr_pool_t *p, DWORD dwProcessId, 
+static int send_listeners_to_child(apr_pool_t *p, DWORD dwProcessId,
                                    apr_file_t *child_in)
 {
     apr_status_t rv;
     int lcnt = 0;
     ap_listen_rec *lr;
     LPWSAPROTOCOL_INFO  lpWSAProtocolInfo;
-    DWORD BytesWritten;
+    apr_size_t BytesWritten;
 
-    /* Run the chain of open sockets. For each socket, duplicate it 
-     * for the target process then send the WSAPROTOCOL_INFO 
+    /* Run the chain of open sockets. For each socket, duplicate it
+     * for the target process then send the WSAPROTOCOL_INFO
      * (returned by dup socket) to the child.
      */
     for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) {
-        int nsd;
+        apr_os_sock_t nsd;
         lpWSAProtocolInfo = apr_pcalloc(p, sizeof(WSAPROTOCOL_INFO));
         apr_os_sock_get(&nsd,lr->sd);
         ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, ap_server_conf,
-                     "Parent: Duplicating socket %d and sending it to child process %d", 
+                     "Parent: Duplicating socket %d and sending it to child process %d",
                      nsd, dwProcessId);
         if (WSADuplicateSocket(nsd, dwProcessId,
                                lpWSAProtocolInfo) == SOCKET_ERROR) {
@@ -633,7 +507,7 @@ static int send_listeners_to_child(apr_pool_t *p, DWORD dwProcessId,
             return -1;
         }
 
-        if ((rv = apr_file_write_full(child_in, lpWSAProtocolInfo, 
+        if ((rv = apr_file_write_full(child_in, lpWSAProtocolInfo,
                                       sizeof(WSAPROTOCOL_INFO), &BytesWritten))
                 != APR_SUCCESS) {
             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
@@ -652,30 +526,29 @@ enum waitlist_e {
     waitlist_term = 1
 };
 
-static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_event, 
+static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_event,
                           DWORD *child_pid)
 {
-    /* These NEVER change for the lifetime of this parent 
+    /* These NEVER change for the lifetime of this parent
      */
     static char **args = NULL;
-    static char **env = NULL;
     static char pidbuf[28];
 
     apr_status_t rv;
     apr_pool_t *ptemp;
     apr_procattr_t *attr;
-    apr_file_t *child_out;
-    apr_file_t *child_err;
     apr_proc_t new_child;
     HANDLE hExitEvent;
     HANDLE waitlist[2];  /* see waitlist_e */
     char *cmd;
     char *cwd;
+    char **env;
+    int envc;
 
-    apr_pool_sub_make(&ptemp, p, NULL);
+    apr_pool_create_ex(&ptemp, p, NULL, NULL);
 
     /* Build the command line. Should look something like this:
-     * C:/apache/bin/apache.exe -f ap_server_confname 
+     * C:/apache/bin/httpd.exe -f ap_server_confname
      * First, get the path to the executable...
      */
     apr_procattr_create(&attr, ptemp);
@@ -688,20 +561,20 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
     }
 
     if (!args) {
-        /* Build the args array, only once since it won't change 
+        /* Build the args array, only once since it won't change
          * for the lifetime of this parent process.
          */
         if ((rv = ap_os_proc_filepath(&cmd, ptemp))
                 != APR_SUCCESS) {
             ap_log_error(APLOG_MARK, APLOG_CRIT, ERROR_BAD_PATHNAME, ap_server_conf,
-                         "Parent: Failed to get full path of %s", 
+                         "Parent: Failed to get full path of %s",
                          ap_server_conf->process->argv[0]);
             apr_pool_destroy(ptemp);
             return -1;
         }
-        
+
         args = malloc((ap_server_conf->process->argc + 1) * sizeof (char*));
-        memcpy(args + 1, ap_server_conf->process->argv + 1, 
+        memcpy(args + 1, ap_server_conf->process->argv + 1,
                (ap_server_conf->process->argc - 1) * sizeof (char*));
         args[0] = malloc(strlen(cmd) + 1);
         strcpy(args[0], cmd);
@@ -712,44 +585,14 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
     }
 
     /* Create a pipe to send handles to the child */
-    if ((rv = apr_procattr_io_set(attr, APR_FULL_BLOCK, 
+    if ((rv = apr_procattr_io_set(attr, APR_FULL_BLOCK,
                                   APR_NO_PIPE, APR_NO_PIPE)) != APR_SUCCESS) {
         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
-                        "Parent: Unable to create child stdin pipe.\n");
-        apr_pool_destroy(ptemp);
-        return -1;
-    }
-
-    /* Open a null handle to soak info from the child */
-    if (((rv = apr_file_open(&child_out, "NUL", APR_READ | APR_WRITE, 
-                             APR_OS_DEFAULT, ptemp)) != APR_SUCCESS)
-        || ((rv = apr_procattr_child_out_set(attr, child_out, NULL)) 
-                != APR_SUCCESS)) {
-        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
-                        "Parent: Unable to connect child stdout to NUL.\n");
+                        "Parent: Unable to create child stdin pipe.");
         apr_pool_destroy(ptemp);
         return -1;
     }
 
-    /* Connect the child's initial stderr to our main server error log 
-     * or share our own stderr handle.
-     */
-    if (ap_server_conf->error_log) {
-        child_err = ap_server_conf->error_log;
-    }
-    else {
-        rv = apr_file_open_stderr(&child_err, ptemp);
-    }
-    if (rv == APR_SUCCESS) {
-        if ((rv = apr_procattr_child_err_set(attr, child_err, NULL))
-                != APR_SUCCESS) {
-            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
-                            "Parent: Unable to connect child stderr.\n");
-            apr_pool_destroy(ptemp);
-            return -1;
-        }
-    }
-
     /* Create the child_ready_event */
     waitlist[waitlist_ready] = CreateEvent(NULL, TRUE, FALSE, NULL);
     if (!waitlist[waitlist_ready]) {
@@ -769,21 +612,15 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
         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;
+    /* Build the env array */
+    for (envc = 0; _environ[envc]; ++envc) {
+        ;
     }
+    env = apr_palloc(ptemp, (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) {
@@ -804,7 +641,7 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
                               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 
+         * We toggle the child's exit event to cause this child
          * to quit even as it is attempting to start.
          */
         SetEvent(hExitEvent);
@@ -817,7 +654,7 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
 
     /* Important:
      * Give the child process a chance to run before dup'ing the sockets.
-     * We have already set the listening sockets noninheritable, but if 
+     * We have already set the listening sockets noninheritable, but if
      * WSADuplicateSocket runs before the child process initializes
      * the listeners will be inherited anyway.
      */
@@ -825,7 +662,7 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
     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);
@@ -838,7 +675,7 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
     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 
+         * We toggle the child's exit event to cause this child
          * to quit even as it is attempting to start.
          */
         SetEvent(hExitEvent);
@@ -848,6 +685,8 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
         return -1;
     }
 
+    apr_file_close(new_child.in);
+
     *child_exit_event = hExitEvent;
     *child_proc = new_child.hproc;
     *child_pid = new_child.pid;
@@ -857,8 +696,8 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
 
 /***********************************************************************
  * master_main()
- * master_main() runs in the parent process.  It creates the child 
- * process which handles HTTP requests then waits on one of three 
+ * 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
@@ -867,15 +706,15 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
  * 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 
+ * 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 
+ * shutdown_event
  * --------------
- * The shutdown event causes master_main to tell the child process to 
+ * 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
@@ -885,11 +724,11 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
  *
  * child process handle
  * --------------------
- * The child process handle will be signaled if the child process 
+ * 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 
+ * robustness, master_main will restart the child process under this
  * condtion.
  *
  * master_main uses the child_exit_event to signal the child process
@@ -914,9 +753,9 @@ static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_even
     event_handles[RESTART_HANDLE] = restart_event;
 
     /* Create a single child process */
-    rv = create_process(pconf, &event_handles[CHILD_HANDLE], 
+    rv = create_process(pconf, &event_handles[CHILD_HANDLE],
                         &child_exit_event, &child_pid);
-    if (rv < 0) 
+    if (rv < 0)
     {
         ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
                      "master_main: create child process failed. Exiting.");
@@ -934,6 +773,7 @@ static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_even
     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) {
@@ -951,7 +791,7 @@ static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_even
     else if (cld == SHUTDOWN_HANDLE) {
         /* shutdown_event signalled */
         shutdown_pending = 1;
-        ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, s, 
+        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,
@@ -959,11 +799,11 @@ static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_even
         }
     }
     else if (cld == RESTART_HANDLE) {
-        /* Received a restart event. Prepare the restart_event to be reused 
-         * then signal the child process to exit. 
+        /* 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, 
+        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,
@@ -971,10 +811,10 @@ static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_even
         }
         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.", 
+                         "Parent: SetEvent for child process %d failed.",
                          event_handles[CHILD_HANDLE]);
         }
-        /* Don't wait to verify that the child process really exits, 
+        /* Don't wait to verify that the child process really exits,
          * just move on with the restart.
          */
         CloseHandle(event_handles[CHILD_HANDLE]);
@@ -987,16 +827,17 @@ static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_even
             /* HUH? We did exit, didn't we? */
             exitcode = APEXIT_CHILDFATAL;
         }
-        if (   exitcode == APEXIT_CHILDFATAL 
+        if (   exitcode == APEXIT_CHILDFATAL
             || exitcode == APEXIT_CHILDINIT
             || exitcode == APEXIT_INIT) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, 
+            ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf,
                          "Parent: child process exited with status %u -- Aborting.", exitcode);
+            shutdown_pending = 1;
         }
         else {
             int i;
             restart_pending = 1;
-            ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, 
+            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);
@@ -1010,11 +851,12 @@ static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_even
         ap_scoreboard_image->global->running_generation = ap_my_generation;
     }
 die_now:
-    if (shutdown_pending) 
+    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 
+        /* 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.
          */
@@ -1042,13 +884,15 @@ die_now:
                 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 
+/* 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;
@@ -1082,7 +926,7 @@ AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
         case AP_MPMQ_MIN_SPARE_DAEMONS:
             *result = 0;
             return APR_SUCCESS;
-        case AP_MPMQ_MIN_SPARE_THREADS:    
+        case AP_MPMQ_MIN_SPARE_THREADS:
             *result = 0;
             return APR_SUCCESS;
         case AP_MPMQ_MAX_SPARE_DAEMONS:
@@ -1097,9 +941,12 @@ AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
         case AP_MPMQ_MAX_DAEMONS:
             *result = 0;
             return APR_SUCCESS;
+        case AP_MPMQ_MPM_STATE:
+            *result = winnt_mpm_state;
+            return APR_SUCCESS;
     }
     return APR_ENOTIMPL;
-} 
+}
 
 #define SERVICE_UNSET (-1)
 static apr_status_t service_set = SERVICE_UNSET;
@@ -1107,13 +954,14 @@ static apr_status_t service_to_start_success;
 static int inst_argc;
 static const char * const *inst_argv;
 static char *service_name = NULL;
-    
-void winnt_rewrite_args(process_rec *process) 
+
+void winnt_rewrite_args(process_rec *process)
 {
     /* Handle the following SCM aspects in this phase:
      *
-     *   -k runservice [transition for WinNT, nothing for Win9x]
-     *   -k (!)install [error out if name is not installed]
+     *   -k runservice [transition in service context only]
+     *   -k install
+     *   -k config
      *   -k uninstall
      *   -k stop
      *   -k shutdown (same as -k stop). Maintained for backward compatability.
@@ -1134,22 +982,65 @@ void winnt_rewrite_args(process_rec *process)
     apr_getopt_t *opt;
     int running_as_service = 1;
     int errout = 0;
+    apr_file_t *nullfile;
 
     pconf = process->pconf;
 
     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
     GetVersionEx(&osver);
 
+    /* We wish this was *always* a reservation, but sadly it wasn't so and
+     * we couldn't break a hard limit prior to NT Kernel 5.1
+     */
+    if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT 
+        && ((osver.dwMajorVersion > 5)
+         || ((osver.dwMajorVersion == 5) && (osver.dwMinorVersion > 0)))) {
+        stack_res_flag = STACK_SIZE_PARAM_IS_A_RESERVATION;
+    }
+
     /* AP_PARENT_PID is only valid in the child */
     pid = getenv("AP_PARENT_PID");
-    if (pid) 
+    if (pid)
     {
+        HANDLE filehand;
+        HANDLE hproc = GetCurrentProcess();
+
         /* This is the child */
         my_pid = GetCurrentProcessId();
         parent_pid = (DWORD) atol(pid);
 
         /* Prevent holding open the (nonexistant) console */
-        real_exit_code = 0;
+        ap_real_exit_code = 0;
+
+        /* The parent gave us stdin, we need to remember this
+         * handle, and no longer inherit it at our children
+         * (we can't slurp it up now, we just aren't ready yet).
+         * The original handle is closed below, at apr_file_dup2()
+         */
+        pipe = GetStdHandle(STD_INPUT_HANDLE);
+        if (DuplicateHandle(hproc, pipe,
+                            hproc, &filehand, 0, FALSE,
+                            DUPLICATE_SAME_ACCESS)) {
+            pipe = filehand;
+        }
+
+        /* The parent gave us stdout of the NUL device,
+         * and expects us to suck up stdin of all of our
+         * shared handles and data from the parent.
+         * Don't infect child processes with our stdin
+         * handle, use another handle to NUL!
+         */
+        {
+            apr_file_t *infile, *outfile;
+            if ((apr_file_open_stdout(&outfile, process->pool) == APR_SUCCESS)
+             && (apr_file_open_stdin(&infile, process->pool) == APR_SUCCESS))
+                apr_file_dup2(infile, outfile, process->pool);
+        }
+
+        /* This child needs the existing stderr opened for logging,
+         * already 
+         */
+
 
         /* The parent is responsible for providing the
          * COMPLETE ARGUMENTS REQUIRED to the child.
@@ -1161,19 +1052,19 @@ void winnt_rewrite_args(process_rec *process)
         signal_arg = "runchild";
         return;
     }
-    
+
     /* This is the parent, we have a long way to go :-) */
     parent_pid = my_pid = GetCurrentProcessId();
 
     /* This behavior is voided by setting real_exit_code to 0 */
     atexit(hold_console_open_on_error);
 
-    /* Rewrite process->argv[]; 
+    /* Rewrite process->argv[];
      *
      * strip out -k signal into signal_arg
      * strip out -n servicename and set the names
      * add default -d serverroot from the path of this executable
-     * 
+     *
      * The end result will look like:
      *
      * The invocation command (%0)
@@ -1183,26 +1074,26 @@ void winnt_rewrite_args(process_rec *process)
      */
     if ((rv = ap_os_proc_filepath(&binpath, process->pconf))
             != APR_SUCCESS) {
-        ap_log_error(APLOG_MARK,APLOG_CRIT, rv, NULL, 
+        ap_log_error(APLOG_MARK,APLOG_CRIT, rv, NULL,
                      "Failed to get the full path of %s", process->argv[0]);
         exit(APEXIT_INIT);
     }
     /* WARNING: There is an implict assumption here that the
      * executable resides in ServerRoot or ServerRoot\bin
      */
-    def_server_root = (char *) apr_filename_of_pathname(binpath);
+    def_server_root = (char *) apr_filepath_name_get(binpath);
     if (def_server_root > binpath) {
         *(def_server_root - 1) = '\0';
-        def_server_root = (char *) apr_filename_of_pathname(binpath);
+        def_server_root = (char *) apr_filepath_name_get(binpath);
         if (!strcasecmp(def_server_root, "bin"))
             *(def_server_root - 1) = '\0';
     }
-    apr_filepath_merge(&def_server_root, NULL, binpath, 
+    apr_filepath_merge(&def_server_root, NULL, binpath,
                        APR_FILEPATH_TRUENAME, process->pool);
 
     /* Use process->pool so that the rewritten argv
      * lasts for the lifetime of the server process,
-     * because pconf will be destroyed after the 
+     * because pconf will be destroyed after the
      * initial pre-flight of the config parser.
      */
     mpm_new_argv = apr_array_make(process->pool, process->argc + 2,
@@ -1217,20 +1108,20 @@ void winnt_rewrite_args(process_rec *process)
     optbuf[2] = '\0';
     apr_getopt_init(&opt, process->pool, process->argc, (char**) process->argv);
     opt->errfn = NULL;
-    while ((rv = apr_getopt(opt, "wn:k:" AP_SERVER_BASEARGS, 
+    while ((rv = apr_getopt(opt, "wn:k:" AP_SERVER_BASEARGS,
                             optbuf + 1, &optarg)) == APR_SUCCESS) {
         switch (optbuf[1]) {
 
         /* Shortcuts; include the -w option to hold the window open on error.
-         * This must not be toggled once we reset real_exit_code to 0!
+         * This must not be toggled once we reset ap_real_exit_code to 0!
          */
         case 'w':
-            if (real_exit_code)
-                real_exit_code = 2;
+            if (ap_real_exit_code)
+                ap_real_exit_code = 2;
             break;
 
         case 'n':
-            service_set = mpm_service_set_name(process->pool, &service_name, 
+            service_set = mpm_service_set_name(process->pool, &service_name,
                                                optarg);
             break;
 
@@ -1251,7 +1142,7 @@ void winnt_rewrite_args(process_rec *process)
             break;
         }
     }
-    
+
     /* back up to capture the bad argument */
     if (rv == APR_BADCH || rv == APR_BADARG) {
         opt->ind--;
@@ -1272,10 +1163,10 @@ void winnt_rewrite_args(process_rec *process)
         running_as_service = 0;
     }
 
-    if (!strcasecmp(signal_arg, "runservice")) 
+    if (!strcasecmp(signal_arg, "runservice"))
     {
-        /* Start the NT Service _NOW_ because the WinNT SCM is 
-         * expecting us to rapidly assume control of our own 
+        /* Start the NT Service _NOW_ because the WinNT SCM is
+         * expecting us to rapidly assume control of our own
          * process, the SCM will tell us our service name, and
          * may have extra StartService() command arguments to
          * add for us.
@@ -1287,7 +1178,7 @@ void winnt_rewrite_args(process_rec *process)
          * (path to apache root, above /bin) for safety.
          */
         apr_filepath_set(def_server_root, process->pool);
-        
+
         /* Any other process has a console, so we don't to begin
          * a Win9x service until the configuration is parsed and
          * any command line errors are reported.
@@ -1295,16 +1186,28 @@ void winnt_rewrite_args(process_rec *process)
          * We hold the return value so that we can die in pre_config
          * after logging begins, and the failure can land in the log.
          */
-        if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) 
-        {
-            if (!errout) {
-                mpm_nt_eventlog_stderr_open(service_name, process->pool);
-            }
-            service_to_start_success = mpm_service_to_start(&service_name,
-                                                            process->pool);
-            if (service_to_start_success == APR_SUCCESS) {
-                service_set = APR_SUCCESS;
-            }
+        if (!errout) {
+            mpm_nt_eventlog_stderr_open(service_name, process->pool);
+        }
+        service_to_start_success = mpm_service_to_start(&service_name,
+                                                        process->pool);
+        if (service_to_start_success == APR_SUCCESS) {
+            service_set = APR_SUCCESS;
+        }
+
+        /* Open a null handle to soak stdout in this process.
+         * Windows service processes are missing any file handle
+         * usable for stdin/out/err.  This was the cause of later 
+         * trouble with invocations of apr_file_open_stdout()
+         */
+        if ((rv = apr_file_open(&nullfile, "NUL",
+                                APR_READ | APR_WRITE, APR_OS_DEFAULT,
+                                process->pool)) == APR_SUCCESS) {
+            apr_file_t *nullstdout;
+            if (apr_file_open_stdout(&nullstdout, process->pool)
+                    == APR_SUCCESS)
+                apr_file_dup2(nullstdout, nullfile, process->pool);
+            apr_file_close(nullfile);
         }
     }
 
@@ -1316,7 +1219,7 @@ void winnt_rewrite_args(process_rec *process)
 
     if (!strcasecmp(signal_arg, "install")) /* -k install */
     {
-        if (service_set == APR_SUCCESS) 
+        if (service_set == APR_SUCCESS)
         {
             ap_log_error(APLOG_MARK,APLOG_ERR, 0, NULL,
                  "%s: Service is already installed.", service_name);
@@ -1325,9 +1228,9 @@ void winnt_rewrite_args(process_rec *process)
     }
     else if (running_as_service)
     {
-        if (service_set == APR_SUCCESS) 
+        if (service_set == APR_SUCCESS)
         {
-            /* Attempt to Uninstall, or stop, before 
+            /* Attempt to Uninstall, or stop, before
              * we can read the arguments or .conf files
              */
             if (!strcasecmp(signal_arg, "uninstall")) {
@@ -1335,13 +1238,13 @@ void winnt_rewrite_args(process_rec *process)
                 exit(rv);
             }
 
-            if ((!strcasecmp(signal_arg, "stop")) || 
+            if ((!strcasecmp(signal_arg, "stop")) ||
                 (!strcasecmp(signal_arg, "shutdown"))) {
                 mpm_signal_service(process->pool, 0);
                 exit(0);
             }
 
-            rv = mpm_merge_service_args(process->pool, mpm_new_argv, 
+            rv = mpm_merge_service_args(process->pool, mpm_new_argv,
                                         fixed_args);
             if (rv == APR_SUCCESS) {
                 ap_log_error(APLOG_MARK,APLOG_INFO, 0, NULL,
@@ -1361,13 +1264,13 @@ void winnt_rewrite_args(process_rec *process)
             exit(APEXIT_INIT);
         }
     }
-    if (strcasecmp(signal_arg, "install") && service_set && service_set != SERVICE_UNSET) 
+    if (strcasecmp(signal_arg, "install") && service_set && service_set != SERVICE_UNSET)
     {
         ap_log_error(APLOG_MARK,APLOG_ERR, service_set, NULL,
              "No installed service named \"%s\".", service_name);
         exit(APEXIT_INIT);
     }
-    
+
     /* Track the args actually entered by the user.
      * These will be used for the -k install parameters, as well as
      * for the -k start service override arguments.
@@ -1375,19 +1278,46 @@ void winnt_rewrite_args(process_rec *process)
     inst_argv = (const char * const *)mpm_new_argv->elts
         + mpm_new_argv->nelts - inst_argc;
 
-    process->argc = mpm_new_argv->nelts; 
+    /* Now, do service install or reconfigure then proceed to
+     * post_config to test the installed configuration.
+     */
+    if (!strcasecmp(signal_arg, "config")) { /* -k config */
+        /* Reconfigure the service */
+        rv = mpm_service_install(process->pool, inst_argc, inst_argv, 1);
+        if (rv != APR_SUCCESS) {
+            exit(rv);
+        }
+
+        fprintf(stderr,"Testing httpd.conf....\n");
+        fprintf(stderr,"Errors reported here must be corrected before the "
+                "service can be started.\n");
+    }
+    else if (!strcasecmp(signal_arg, "install")) { /* -k install */
+        /* Install the service */
+        rv = mpm_service_install(process->pool, inst_argc, inst_argv, 0);
+        if (rv != APR_SUCCESS) {
+            exit(rv);
+        }
+
+        fprintf(stderr,"Testing httpd.conf....\n");
+        fprintf(stderr,"Errors reported here must be corrected before the "
+                "service can be started.\n");
+    }
+
+    process->argc = mpm_new_argv->nelts;
     process->argv = (const char * const *) mpm_new_argv->elts;
 }
 
 
-static int winnt_pre_config(apr_pool_t *pconf_, apr_pool_t *plog, apr_pool_t *ptemp) 
+static int winnt_pre_config(apr_pool_t *pconf_, apr_pool_t *plog, apr_pool_t *ptemp)
 {
     /* Handle the following SCM aspects in this phase:
      *
      *   -k runservice [WinNT errors logged from rewrite_args]
      */
 
-    /* Initialize shared static objects. 
+    /* Initialize shared static objects.
+     * TODO: Put config related statics into an sconf structure.
      */
     pconf = pconf_;
 
@@ -1395,25 +1325,146 @@ static int winnt_pre_config(apr_pool_t *pconf_, apr_pool_t *plog, apr_pool_t *pt
         ap_exists_config_define("DEBUG"))
         one_process = -1;
 
+    /* XXX: presume proper privilages; one nice thing would be
+     * a loud emit if running as "LocalSystem"/"SYSTEM" to indicate
+     * they should change to a user with write access to logs/ alone.
+     */
+    ap_sys_privileges_handlers(1);
+
     if (!strcasecmp(signal_arg, "runservice")
-            && (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
             && (service_to_start_success != APR_SUCCESS)) {
-        ap_log_error(APLOG_MARK,APLOG_CRIT, service_to_start_success, NULL, 
+        ap_log_error(APLOG_MARK,APLOG_CRIT, service_to_start_success, NULL,
                      "%s: Unable to start the service manager.",
                      service_name);
         exit(APEXIT_INIT);
     }
+    else if (!one_process && !ap_my_generation) {
+        /* Open a null handle to soak stdout in this process.
+         * We need to emulate apr_proc_detach, unix performs this
+         * same check in the pre_config hook (although it is
+         * arguably premature).  Services already fixed this.
+         */
+        apr_file_t *nullfile;
+        apr_status_t rv;
+        apr_pool_t *pproc = apr_pool_parent_get(pconf);
+
+        if ((rv = apr_file_open(&nullfile, "NUL",
+                                APR_READ | APR_WRITE, APR_OS_DEFAULT,
+                                pproc)) == APR_SUCCESS) {
+            apr_file_t *nullstdout;
+            if (apr_file_open_stdout(&nullstdout, pproc)
+                    == APR_SUCCESS)
+                apr_file_dup2(nullstdout, nullfile, pproc);
+            apr_file_close(nullfile);
+        }
+    }
 
     ap_listen_pre_config();
+    thread_limit = DEFAULT_THREAD_LIMIT;
     ap_threads_per_child = DEFAULT_THREADS_PER_CHILD;
     ap_pid_fname = DEFAULT_PIDLOG;
     ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
+    ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
 
     apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
 
     return OK;
 }
 
+static int winnt_check_config(apr_pool_t *pconf, apr_pool_t *plog,
+                              apr_pool_t *ptemp, server_rec* s)
+{
+    int is_parent;
+    static int restart_num = 0;
+    int startup = 0;
+
+    /* We want this only in the parent and only the first time around */
+    is_parent = (parent_pid == my_pid);
+    if (is_parent && restart_num++ == 0) {
+        startup = 1;
+    }
+
+    if (thread_limit > MAX_THREAD_LIMIT) {
+        if (startup) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
+                         "WARNING: ThreadLimit of %d exceeds compile-time "
+                         "limit of", thread_limit);
+            ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
+                         " %d threads, decreasing to %d.",
+                         MAX_THREAD_LIMIT, MAX_THREAD_LIMIT);
+        } else if (is_parent) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
+                         "ThreadLimit of %d exceeds compile-time limit "
+                         "of %d, decreasing to match",
+                         thread_limit, MAX_THREAD_LIMIT);
+        }
+        thread_limit = MAX_THREAD_LIMIT;
+    }
+    else if (thread_limit < 1) {
+        if (startup) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
+                         "WARNING: ThreadLimit of %d not allowed, "
+                         "increasing to 1.", thread_limit);
+        } else if (is_parent) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
+                         "ThreadLimit of %d not allowed, increasing to 1",
+                         thread_limit);
+        }
+        thread_limit = 1;
+    }
+
+    /* You cannot change ThreadLimit across a restart; ignore
+     * any such attempts.
+     */
+    if (!first_thread_limit) {
+        first_thread_limit = thread_limit;
+    }
+    else if (thread_limit != first_thread_limit) {
+        /* Don't need a startup console version here */
+        if (is_parent) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
+                         "changing ThreadLimit to %d from original value "
+                         "of %d not allowed during restart",
+                         thread_limit, first_thread_limit);
+        }
+        thread_limit = first_thread_limit;
+    }
+
+    if (ap_threads_per_child > thread_limit) {
+        if (startup) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
+                         "WARNING: ThreadsPerChild of %d exceeds ThreadLimit "
+                         "of", ap_threads_per_child);
+            ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
+                         " %d threads, decreasing to %d.",
+                         thread_limit, thread_limit);
+            ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
+                         " To increase, please see the ThreadLimit "
+                         "directive.");
+        } else if (is_parent) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
+                         "ThreadsPerChild of %d exceeds ThreadLimit "
+                         "of %d, decreasing to match",
+                         ap_threads_per_child, thread_limit);
+        }
+        ap_threads_per_child = thread_limit;
+    }
+    else if (ap_threads_per_child < 1) {
+        if (startup) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
+                         "WARNING: ThreadsPerChild of %d not allowed, "
+                         "increasing to 1.", ap_threads_per_child);
+        } else if (is_parent) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
+                         "ThreadsPerChild of %d not allowed, increasing to 1",
+                         ap_threads_per_child);
+        }
+        ap_threads_per_child = 1;
+    }
+
+    return OK;
+}
+
 static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec* s)
 {
     static int restart_num = 0;
@@ -1421,8 +1472,8 @@ static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pt
 
     /* Handle the following SCM aspects in this phase:
      *
-     *   -k install
-     *   -k config
+     *   -k install (catch and exit as install was handled in rewrite_args)
+     *   -k config  (catch and exit as config was handled in rewrite_args)
      *   -k start
      *   -k restart
      *   -k runservice [Win95, only once - after we parsed the config]
@@ -1435,12 +1486,22 @@ static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pt
      */
 
     if (!strcasecmp(signal_arg, "install")) {
-        rv = mpm_service_install(ptemp, inst_argc, inst_argv, 0);
-        exit (rv);
+        /* Service install happens in the rewrite_args hooks. If we
+         * made it this far, the server configuration is clean and the
+         * service will successfully start.
+         */
+        apr_pool_destroy(s->process->pool);
+        apr_terminate();
+        exit(0);
     }
     if (!strcasecmp(signal_arg, "config")) {
-        rv = mpm_service_install(ptemp, inst_argc, inst_argv, 1);
-        exit (rv);
+        /* Service reconfiguration happens in the rewrite_args hooks. If we
+         * made it this far, the server configuration is clean and the
+         * service will successfully start.
+         */
+        apr_pool_destroy(s->process->pool);
+        apr_terminate();
+        exit(0);
     }
 
     if (!strcasecmp(signal_arg, "start")) {
@@ -1452,17 +1513,21 @@ static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pt
             lr->active = 0;
         }
         rv = mpm_service_start(ptemp, inst_argc, inst_argv);
+        apr_pool_destroy(s->process->pool);
+        apr_terminate();
         exit (rv);
     }
 
     if (!strcasecmp(signal_arg, "restart")) {
         mpm_signal_service(ptemp, 1);
+        apr_pool_destroy(s->process->pool);
+        apr_terminate();
         exit (rv);
     }
 
-    if (parent_pid == my_pid) 
+    if (parent_pid == my_pid)
     {
-        if (restart_num++ == 1) 
+        if (restart_num++ == 1)
         {
             /* This code should be run once in the parent and not run
              * across a restart
@@ -1471,8 +1536,8 @@ static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pt
             setup_signal_names(apr_psprintf(pconf,"ap%d", parent_pid));
 
             ap_log_pid(pconf, ap_pid_fname);
-            
-            /* Create shutdown event, apPID_shutdown, where PID is the parent 
+
+            /* Create shutdown event, apPID_shutdown, where PID is the parent
              * Apache process ID. Shutdown is signaled by 'apache -k shutdown'.
              */
             shutdown_event = CreateEvent(sa, FALSE, FALSE, signal_shutdown_name);
@@ -1483,7 +1548,7 @@ static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pt
                 return HTTP_INTERNAL_SERVER_ERROR;
             }
 
-            /* Create restart event, apPID_restart, where PID is the parent 
+            /* Create restart event, apPID_restart, where PID is the parent
              * Apache process ID. Restart is signaled by 'apache -k restart'.
              */
             restart_event = CreateEvent(sa, FALSE, FALSE, signal_restart_name);
@@ -1496,32 +1561,8 @@ static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pt
             }
             CleanNullACL((void *)sa);
 
-            /* Now that we are flying at 15000 feet... 
-             * wipe out the Win95 service console,
-             * signal the SCM the WinNT service started, or
-             * if not a service, setup console handlers instead.
-             */
-            if (!strcasecmp(signal_arg, "runservice"))
-            {
-                if (osver.dwPlatformId != VER_PLATFORM_WIN32_NT) 
-                {
-                    rv = mpm_service_to_start(&service_name,
-                                              s->process->pool);
-                    if (rv != APR_SUCCESS) {
-                        ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf,
-                                     "%s: Unable to start the service manager.",
-                                     service_name);
-                        return HTTP_INTERNAL_SERVER_ERROR;
-                    }
-                }
-            }
-            else /* ! -k runservice */
-            {
-                mpm_start_console_handler();
-            }
-
             /* Create the start mutex, as an unnamed object for security.
-             * Ths start mutex is used during a restart to prevent more than 
+             * Ths start mutex is used during a restart to prevent more than
              * one child process from entering the accept loop at once.
              */
             rv =  apr_proc_mutex_create(&start_mutex, NULL,
@@ -1532,8 +1573,14 @@ static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pt
                              "%s: Unable to create the start_mutex.",
                              service_name);
                 return HTTP_INTERNAL_SERVER_ERROR;
-            }            
+            }
         }
+        /* Always reset our console handler to be the first, even on a restart
+        *  because some modules (e.g. mod_perl) might have set a console 
+        *  handler to terminate the process.
+        */
+        if (strcasecmp(signal_arg, "runservice"))
+            mpm_start_console_handler();
     }
     else /* parent_pid != my_pid */
     {
@@ -1547,7 +1594,7 @@ static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pt
  */
 static int winnt_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
 {
-    /* Initialize shared static objects. 
+    /* Initialize shared static objects.
      */
     ap_server_conf = s;
 
@@ -1557,16 +1604,16 @@ static int winnt_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, s
 
     /* We cannot initialize our listeners if we are restarting
      * (the parent process already has glomed on to them)
-     * nor should we do so for service reconfiguration 
+     * nor should we do so for service reconfiguration
      * (since the service may already be running.)
      */
-    if (!strcasecmp(signal_arg, "restart") 
+    if (!strcasecmp(signal_arg, "restart")
             || !strcasecmp(signal_arg, "config")) {
         return OK;
     }
 
     if (ap_setup_listeners(s) < 1) {
-        ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, 
+        ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0,
                      NULL, "no listening sockets available, shutting down");
         return DONE;
     }
@@ -1583,17 +1630,20 @@ static void winnt_child_init(apr_pool_t *pchild, struct server_rec *s)
     /* This is a child process, not in single process mode */
     if (!one_process) {
         /* Set up events and the scoreboard */
-        get_handles_from_parent(s, &exit_event, &start_mutex, 
+        get_handles_from_parent(s, &exit_event, &start_mutex,
                                 &ap_scoreboard_shm);
 
         /* Set up the listeners */
         get_listeners_from_parent(s);
 
+        /* Done reading from the parent, close that channel */
+        CloseHandle(pipe);
+
         ap_my_generation = ap_scoreboard_image->global->running_generation;
     }
     else {
         /* Single process mode - this lock doesn't even need to exist */
-        rv = apr_proc_mutex_create(&start_mutex, signal_name_prefix, 
+        rv = apr_proc_mutex_create(&start_mutex, signal_name_prefix,
                                    APR_LOCK_DEFAULT, s->process->pool);
         if (rv != APR_SUCCESS) {
             ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf,
@@ -1601,7 +1651,7 @@ static void winnt_child_init(apr_pool_t *pchild, struct server_rec *s)
                          service_name, my_pid);
             exit(APEXIT_CHILDINIT);
         }
-        
+
         /* Borrow the shutdown_even as our _child_ loop exit event */
         exit_event = shutdown_event;
     }
@@ -1612,20 +1662,9 @@ AP_DECLARE(int) ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s )
 {
     static int restart = 0;            /* Default is "not a restart" */
 
-    if (!restart) {
-        first_thread_limit = thread_limit;
-    }
-
-    if (changed_limit_at_restart) {
-        ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, ap_server_conf,
-                     "WARNING: Attempt to change ThreadLimit ignored "
-                     "during restart");
-        changed_limit_at_restart = 0;
-    }
-    
-    /* ### If non-graceful restarts are ever introduced - we need to rerun 
-     * the pre_mpm hook on subsequent non-graceful restarts.  But Win32 
-     * has only graceful style restarts - and we need this hook to act 
+    /* ### If non-graceful restarts are ever introduced - we need to rerun
+     * the pre_mpm hook on subsequent non-graceful restarts.  But Win32
+     * has only graceful style restarts - and we need this hook to act
      * the same on Win32 as on Unix.
      */
     if (!restart && ((parent_pid == my_pid) || one_process)) {
@@ -1634,10 +1673,10 @@ AP_DECLARE(int) ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s )
             return 1;
         }
     }
-    
-    if ((parent_pid != my_pid) || one_process) 
+
+    if ((parent_pid != my_pid) || one_process)
     {
-        /* The child process or in one_process (debug) mode 
+        /* The child process or in one_process (debug) mode
          */
         ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf,
                      "Child %d: Child process is running", my_pid);
@@ -1645,21 +1684,21 @@ AP_DECLARE(int) ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s )
         child_main(pconf);
 
         ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf,
-                     "Child %d: Child process is exiting", my_pid);        
+                     "Child %d: Child process is exiting", my_pid);
         return 1;
     }
-    else 
+    else
     {
         /* A real-honest to goodness parent */
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
                      "%s configured -- resuming normal operations",
-                     ap_get_server_version());
+                     ap_get_server_description());
         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
                      "Server built: %s", ap_get_server_built());
 
         restart = master_main(ap_server_conf, shutdown_event, restart_event);
 
-        if (!restart) 
+        if (!restart)
         {
             /* Shutting down. Clean up... */
             const char *pidfile = ap_server_root_relative (pconf, ap_pid_fname);
@@ -1683,27 +1722,28 @@ AP_DECLARE(int) ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s )
 
 static void winnt_hooks(apr_pool_t *p)
 {
-    /* The prefork open_logs phase must run before the core's, or stderr
+    /* Our open_logs hook function must run before the core's, or stderr
      * will be redirected to a file, and the messages won't print to the
      * console.
      */
     static const char *const aszSucc[] = {"core.c", NULL};
 
     ap_hook_pre_config(winnt_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_check_config(winnt_check_config, NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_post_config(winnt_post_config, NULL, NULL, 0);
     ap_hook_child_init(winnt_child_init, NULL, NULL, APR_HOOK_MIDDLE);
-    ap_hook_open_logs(winnt_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE);
+    ap_hook_open_logs(winnt_open_logs, NULL, aszSucc, APR_HOOK_REALLY_FIRST);
 }
 
 AP_MODULE_DECLARE_DATA module mpm_winnt_module = {
     MPM20_MODULE_STUFF,
-    winnt_rewrite_args,         /* hook to run before apache parses args */
-    NULL,                      /* create per-directory config structure */
-    NULL,                      /* merge per-directory config structures */
-    NULL,                      /* create per-server config structure */
-    NULL,                      /* merge per-server config structures */
-    winnt_cmds,                        /* command apr_table_t */
-    winnt_hooks                /* register_hooks */
+    winnt_rewrite_args,    /* hook to run before apache parses args */
+    NULL,                  /* create per-directory config structure */
+    NULL,                  /* merge per-directory config structures */
+    NULL,                  /* create per-server config structure */
+    NULL,                  /* merge per-server config structures */
+    winnt_cmds,            /* command apr_table_t */
+    winnt_hooks            /* register_hooks */
 };
 
 #endif /* def WIN32 */