Apache HTTPD
mpm_winnt.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifdef WIN32
18
19#include "httpd.h"
20#include "http_main.h"
21#include "http_log.h"
22#include "http_config.h" /* for read_config */
23#include "http_core.h" /* for get_remote_host */
24#include "http_connection.h"
25#include "apr_portable.h"
26#include "apr_thread_proc.h"
27#include "apr_getopt.h"
28#include "apr_strings.h"
29#include "apr_lib.h"
30#include "apr_shm.h"
31#include "apr_thread_mutex.h"
32#include "ap_mpm.h"
33#include "apr_general.h"
34#include "ap_config.h"
35#include "ap_listen.h"
36#include "mpm_default.h"
37#include "mpm_winnt.h"
38#include "mpm_common.h"
39#include <malloc.h>
40#include "apr_atomic.h"
41#include "scoreboard.h"
42
43#ifdef __WATCOMC__
44#define _environ environ
45#endif
46
47#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION /* missing on MinGW */
48#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
49#endif
50
51/* Because ap_setup_listeners() is skipped in the child, any merging
52 * of [::]:80 and 0.0.0.0:80 for AP_ENABLE_V4_MAPPED in the parent
53 * won't have taken place in the child, so the child will expect to
54 * read two sockets for "Listen 80" but the parent will send only
55 * one.
56 */
57#ifdef AP_ENABLE_V4_MAPPED
58#error The WinNT MPM does not currently support AP_ENABLE_V4_MAPPED
59#endif
60
61/* scoreboard.c does the heavy lifting; all we do is create the child
62 * score by moving a handle down the pipe into the child's stdin.
63 */
65
66/* my_generation is returned to the scoreboard code */
67static volatile ap_generation_t my_generation=0;
68
69/* Definitions of WINNT MPM specific config globals */
70static HANDLE shutdown_event; /* used to signal the parent to shutdown */
71static HANDLE restart_event; /* used to signal the parent to restart */
72
73static int one_process = 0;
74static char const* signal_arg = NULL;
75
76OSVERSIONINFO osver; /* VER_PLATFORM_WIN32_NT */
77
78/* set by child_main to STACK_SIZE_PARAM_IS_A_RESERVATION for NT >= 5.1 (XP/2003) */
80
81static DWORD parent_pid;
83
84/* used by parent to signal the child to start and exit */
87
89static int thread_limit = 0;
90static int first_thread_limit = 0;
92
93/* shared by service.c as global, although
94 * perhaps it should be private.
95 */
97
98/* Only one of these, the pipe from our parent, meant only for
99 * one child worker's consumption (not to be inherited!)
100 * XXX: decorate this name for the trunk branch, was left simplified
101 * only to make the 2.2 patch trivial to read.
102 */
103static HANDLE pipe;
104
105/*
106 * Command processors
107 */
108
109static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, const char *arg)
110{
111 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
112 if (err != NULL) {
113 return err;
114 }
115
117 return NULL;
118}
119static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg)
120{
121 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
122 if (err != NULL) {
123 return err;
124 }
125
127 return NULL;
128}
129
130static const command_rec winnt_cmds[] = {
133 "Number of threads each child creates" ),
135 "Maximum worker threads in a server for this run of Apache"),
136{ NULL }
137};
138
139static void winnt_note_child_started(int slot, pid_t pid)
140{
146}
147
148static void winnt_note_child_killed(int slot)
149{
155}
156
157/*
158 * Signalling Apache on NT.
159 *
160 * Under Unix, Apache can be told to shutdown or restart by sending various
161 * signals (HUP, USR, TERM). On NT we don't have easy access to signals, so
162 * we use "events" instead. The parent apache process goes into a loop
163 * where it waits forever for a set of events. Two of those events are
164 * called
165 *
166 * apPID_shutdown
167 * apPID_restart
168 *
169 * (where PID is the PID of the apache parent process). When one of these
170 * is signalled, the Apache parent performs the appropriate action. The events
171 * can become signalled through internal Apache methods (e.g. if the child
172 * finds a fatal error and needs to kill its parent), via the service
173 * control manager (the control thread will signal the shutdown event when
174 * requested to stop the Apache service), from the -k Apache command line,
175 * or from any external program which finds the Apache PID from the
176 * httpd.pid file.
177 *
178 * The signal_parent() function, below, is used to signal one of these events.
179 * It can be called by any child or parent process, since it does not
180 * rely on global variables.
181 *
182 * On entry, type gives the event to signal. 0 means shutdown, 1 means
183 * graceful restart.
184 */
185/*
186 * Initialise the signal names, in the global variables signal_name_prefix,
187 * signal_restart_name and signal_shutdown_name.
188 */
189#define MAX_SIGNAL_NAME 30 /* Long enough for apPID_shutdown, where PID is an int */
193static void setup_signal_names(char *prefix)
194{
197 "%s_shutdown", signal_name_prefix);
199 "%s_restart", signal_name_prefix);
200}
201
203{
204 HANDLE e;
205 char *signal_name;
206
207 if (parent_pid == my_pid) {
208 switch(type) {
210 {
212 break;
213 }
214 /* This MPM supports only graceful restarts right now */
217 {
219 break;
220 }
221 }
222 return;
223 }
224
225 switch(type) {
227 {
229 break;
230 }
231 /* This MPM supports only graceful restarts right now */
234 {
236 break;
237 }
238 default:
239 return;
240 }
241
243 if (!e) {
244 /* Um, problem, can't signal the parent, which means we can't
245 * signal ourselves to die. Ignore for now...
246 */
248 "OpenEvent on %s event", signal_name);
249 return;
250 }
251 if (SetEvent(e) == 0) {
252 /* Same problem as above */
254 "SetEvent on %s event", signal_name);
255 CloseHandle(e);
256 return;
257 }
258 CloseHandle(e);
259}
260
261
262/*
263 * Passed the following handles [in sync with send_handles_to_child()]
264 *
265 * ready event [signal the parent immediately, then close]
266 * exit event [save to poll later]
267 * start mutex [signal from the parent to begin accept()]
268 * scoreboard shm handle [to recreate the ap_scoreboard]
269 */
273{
278 void *sb_shared;
279 apr_status_t rv;
280
281 /* *** We now do this way back in winnt_rewrite_args
282 * pipe = GetStdHandle(STD_INPUT_HANDLE);
283 */
284 if (!ReadFile(pipe, &ready_event, sizeof(HANDLE),
286 || (BytesRead != sizeof(HANDLE))) {
288 "Child: Unable to retrieve the ready event from the parent");
290 }
291
294
295 if (!ReadFile(pipe, child_exit_event, sizeof(HANDLE),
297 || (BytesRead != sizeof(HANDLE))) {
299 "Child: Unable to retrieve the exit event from the parent");
301 }
302
303 if (!ReadFile(pipe, &os_start, sizeof(os_start),
305 || (BytesRead != sizeof(os_start))) {
307 "Child: Unable to retrieve the start_mutex from the parent");
309 }
311 if ((rv = apr_os_proc_mutex_put(child_start_mutex, &os_start, s->process->pool))
312 != APR_SUCCESS) {
314 "Child: Unable to access the start_mutex from the parent");
316 }
317
318 if (!ReadFile(pipe, &hScore, sizeof(hScore),
320 || (BytesRead != sizeof(hScore))) {
322 "Child: Unable to retrieve the scoreboard from the parent");
324 }
326 if ((rv = apr_os_shm_put(scoreboard_shm, &hScore, s->process->pool))
327 != APR_SUCCESS) {
329 "Child: Unable to access the scoreboard from the parent");
331 }
332
333 rv = ap_reopen_scoreboard(s->process->pool, scoreboard_shm, 1);
336 "Child: Unable to reopen the scoreboard from the parent");
338 }
339 /* We must 'initialize' the scoreboard to relink all the
340 * process-local pointer arrays into the shared memory block.
341 */
343
345 "Child: Retrieved our scoreboard from the parent.");
346}
347
348
356{
357 apr_status_t rv;
359 HANDLE hDup;
363
365 sizeof(my_generation), NULL))
366 != APR_SUCCESS) {
368 "Parent: Unable to send its generation to the child");
369 return -1;
370 }
374 "Parent: Unable to duplicate the ready event handle for the child");
375 return -1;
376 }
377 if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten))
378 != APR_SUCCESS) {
380 "Parent: Unable to send the exit event handle to the child");
381 return -1;
382 }
386 "Parent: Unable to duplicate the exit event handle for the child");
387 return -1;
388 }
389 if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten))
390 != APR_SUCCESS) {
392 "Parent: Unable to send the exit event handle to the child");
393 return -1;
394 }
397 "Parent: Unable to retrieve the start mutex for the child");
398 return -1;
399 }
401 SYNCHRONIZE, FALSE, 0)) {
403 "Parent: Unable to duplicate the start mutex to the child");
404 return -1;
405 }
406 if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten))
407 != APR_SUCCESS) {
409 "Parent: Unable to send the start mutex to the child");
410 return -1;
411 }
414 "Parent: Unable to retrieve the scoreboard handle for the child");
415 return -1;
416 }
420 "Parent: Unable to duplicate the scoreboard handle to the child");
421 return -1;
422 }
423 if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten))
424 != APR_SUCCESS) {
426 "Parent: Unable to send the scoreboard handle to the child");
427 return -1;
428 }
429
431 "Parent: Sent the scoreboard to the child");
432 return 0;
433}
434
435
436/*
437 * get_listeners_from_parent()
438 * The listen sockets are opened in the parent. This function, which runs
439 * exclusively in the child process, receives them from the parent and
440 * makes them available in the child.
441 */
443{
447 int lcnt = 0;
448 SOCKET nsd;
449
450 /* Set up a default listener if necessary */
451 if (ap_listeners == NULL) {
453 lr = apr_palloc(s->process->pool, sizeof(ap_listen_rec));
454 lr->sd = NULL;
455 lr->next = ap_listeners;
457 }
458
459 /* Open the pipe to the parent process to receive the inherited socket
460 * data. The sockets have been set to listening in the parent process.
461 *
462 * *** We now do this way back in winnt_rewrite_args
463 * pipe = GetStdHandle(STD_INPUT_HANDLE);
464 */
465 for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) {
467 "Child: Waiting for data for listening socket %pI",
468 lr->bind_addr);
469 if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO),
472 "Child: Unable to read socket data from parent");
474 }
475
477 &WSAProtocolInfo, 0, 0);
478 if (nsd == INVALID_SOCKET) {
480 "Child: WSASocket failed to open the inherited socket");
482 }
483
486 "Child: SetHandleInformation failed");
487 }
488 apr_os_sock_put(&lr->sd, &nsd, s->process->pool);
489 }
490
492 "Child: retrieved %d listeners from parent", lcnt);
493}
494
495
498{
499 apr_status_t rv;
500 int lcnt = 0;
504
505 /* Run the chain of open sockets. For each socket, duplicate it
506 * for the target process then send the WSAPROTOCOL_INFO
507 * (returned by dup socket) to the child.
508 */
509 for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) {
512 apr_os_sock_get(&nsd, lr->sd);
514 "Parent: Duplicating socket %d (%pI) and sending it to child process %lu",
515 nsd, lr->bind_addr, dwProcessId);
519 "Parent: WSADuplicateSocket failed for socket %d. Check the FAQ.", nsd);
520 return -1;
521 }
522
525 != APR_SUCCESS) {
527 "Parent: Unable to write duplicated socket %d to the child.", nsd);
528 return -1;
529 }
530 }
531
533 "Parent: Sent %d listeners to child %lu", lcnt, dwProcessId);
534 return 0;
535}
536
537enum waitlist_e {
538 waitlist_ready = 0,
539 waitlist_term = 1
540};
541
544{
545 /* These NEVER change for the lifetime of this parent
546 */
547 static char **args = NULL;
548 static char pidbuf[28];
549
550 apr_status_t rv;
551 apr_pool_t *ptemp;
555 HANDLE waitlist[2]; /* see waitlist_e */
556 char *cmd;
557 char *cwd;
558 char **env;
559 int envc;
560
561 apr_pool_create_ex(&ptemp, p, NULL, NULL);
562 apr_pool_tag(ptemp, "create_process");
563
564 /* Build the command line. Should look something like this:
565 * C:/apache/bin/httpd.exe -f ap_server_confname
566 * First, get the path to the executable...
567 */
568 apr_procattr_create(&attr, ptemp);
571 if (((rv = apr_filepath_get(&cwd, 0, ptemp)) != APR_SUCCESS)
572 || ((rv = apr_procattr_dir_set(attr, cwd)) != APR_SUCCESS)) {
574 "Parent: Failed to get the current path");
575 }
576
577 if (!args) {
578 /* Build the args array, only once since it won't change
579 * for the lifetime of this parent process.
580 */
581 if ((rv = ap_os_proc_filepath(&cmd, ptemp))
582 != APR_SUCCESS) {
584 "Parent: Failed to get full path of %s",
586 apr_pool_destroy(ptemp);
587 return -1;
588 }
589
590 args = ap_malloc((ap_server_conf->process->argc + 1) * sizeof (char*));
592 (ap_server_conf->process->argc - 1) * sizeof (char*));
593 args[0] = ap_malloc(strlen(cmd) + 1);
594 strcpy(args[0], cmd);
596 }
597 else {
598 cmd = args[0];
599 }
600
601 /* Create a pipe to send handles to the child */
605 "Parent: Unable to create child stdin pipe.");
606 apr_pool_destroy(ptemp);
607 return -1;
608 }
609
610 /* Create the child_ready_event */
612 if (!waitlist[waitlist_ready]) {
614 "Parent: Could not create ready event for child process");
615 apr_pool_destroy (ptemp);
616 return -1;
617 }
618
619 /* Create the child_exit_event */
621 if (!hExitEvent) {
623 "Parent: Could not create exit event for child process");
624 apr_pool_destroy(ptemp);
626 return -1;
627 }
628
629 /* Build the env array */
630 for (envc = 0; _environ[envc]; ++envc) {
631 ;
632 }
633 env = apr_palloc(ptemp, (envc + 2) * sizeof (char*));
634 memcpy(env, _environ, envc * sizeof (char*));
635 apr_snprintf(pidbuf, sizeof(pidbuf), "AP_PARENT_PID=%lu", parent_pid);
636 env[envc] = pidbuf;
637 env[envc + 1] = NULL;
638
639 rv = apr_proc_create(&new_child, cmd, (const char * const *)args,
640 (const char * const *)env, attr, ptemp);
641 if (rv != APR_SUCCESS) {
643 "Parent: Failed to create the child process.");
644 apr_pool_destroy(ptemp);
647 CloseHandle(new_child.hproc);
648 return -1;
649 }
650
652 "Parent: Created child process %d", new_child.pid);
653
656 new_child.hproc, new_child.in)) {
657 /*
658 * This error is fatal, mop up the child and move on
659 * We toggle the child's exit event to cause this child
660 * to quit even as it is attempting to start.
661 */
663 apr_pool_destroy(ptemp);
666 CloseHandle(new_child.hproc);
667 return -1;
668 }
669
670 /* Important:
671 * Give the child process a chance to run before dup'ing the sockets.
672 * We have already set the listening sockets noninheritable, but if
673 * WSADuplicateSocket runs before the child process initializes
674 * the listeners will be inherited anyway.
675 */
679 if (rv != WAIT_OBJECT_0) {
680 /*
681 * Outch... that isn't a ready signal. It's dead, Jim!
682 */
684 apr_pool_destroy(ptemp);
686 CloseHandle(new_child.hproc);
687 return -1;
688 }
689
690 if (send_listeners_to_child(ptemp, new_child.pid, new_child.in)) {
691 /*
692 * This error is fatal, mop up the child and move on
693 * We toggle the child's exit event to cause this child
694 * to quit even as it is attempting to start.
695 */
697 apr_pool_destroy(ptemp);
699 CloseHandle(new_child.hproc);
700 return -1;
701 }
702
704
706 *child_proc = new_child.hproc;
707 *child_pid = new_child.pid;
708
709 return 0;
710}
711
712/***********************************************************************
713 * master_main()
714 * master_main() runs in the parent process. It creates the child
715 * process which handles HTTP requests then waits on one of three
716 * events:
717 *
718 * restart_event
719 * -------------
720 * The restart event causes master_main to start a new child process and
721 * tells the old child process to exit (by setting the child_exit_event).
722 * The restart event is set as a result of one of the following:
723 * 1. An apache -k restart command on the command line
724 * 2. A command received from Windows service manager which gets
725 * translated into an ap_signal_parent(SIGNAL_PARENT_RESTART)
726 * call by code in service.c.
727 * 3. The child process calling ap_signal_parent(SIGNAL_PARENT_RESTART)
728 * as a result of hitting MaxConnectionsPerChild.
729 *
730 * shutdown_event
731 * --------------
732 * The shutdown event causes master_main to tell the child process to
733 * exit and that the server is shutting down. The shutdown event is
734 * set as a result of one of the following:
735 * 1. An apache -k shutdown command on the command line
736 * 2. A command received from Windows service manager which gets
737 * translated into an ap_signal_parent(SIGNAL_PARENT_SHUTDOWN)
738 * call by code in service.c.
739 *
740 * child process handle
741 * --------------------
742 * The child process handle will be signaled if the child process
743 * exits for any reason. In a normal running server, the signaling
744 * of this event means that the child process has exited prematurely
745 * due to a seg fault or other irrecoverable error. For server
746 * robustness, master_main will restart the child process under this
747 * condition.
748 *
749 * master_main uses the child_exit_event to signal the child process
750 * to exit.
751 **********************************************************************/
752#define NUM_WAIT_HANDLES 3
753#define CHILD_HANDLE 0
754#define SHUTDOWN_HANDLE 1
755#define RESTART_HANDLE 2
757{
758 int rv, cld;
759 int child_created;
760 int restart_pending;
765
767
770
771 /* Create a single child process */
774 if (rv < 0)
775 {
777 "master_main: create child process failed. Exiting.");
779 goto die_now;
780 }
781
782 child_created = 1;
783
784 if (!strcasecmp(signal_arg, "runservice")) {
786 }
787
788 /* Update the scoreboard. Note that there is only a single active
789 * child at once.
790 */
792 winnt_note_child_started(/* slot */ 0, child_pid);
793
794 /* Wait for shutdown or restart events or for child death */
797 cld = rv - WAIT_OBJECT_0;
798 if (rv == WAIT_FAILED) {
799 /* Something serious is wrong */
801 "master_main: WaitForMultipleObjects WAIT_FAILED -- doing server shutdown");
803 }
804 else if (rv == WAIT_TIMEOUT) {
805 /* Hey, this cannot happen */
807 "master_main: WaitForMultipleObjects with INFINITE wait exited with WAIT_TIMEOUT");
809 }
810 else if (cld == SHUTDOWN_HANDLE) {
811 /* shutdown_event signalled */
814 "Parent: Received shutdown signal -- Shutting down the server.");
815 if (ResetEvent(shutdown_event) == 0) {
817 "ResetEvent(shutdown_event)");
818 }
819 }
820 else if (cld == RESTART_HANDLE) {
821 /* Received a restart event. Prepare the restart_event to be reused
822 * then signal the child process to exit.
823 */
824 restart_pending = 1;
826 "Parent: Received restart signal -- Restarting the server.");
827 if (ResetEvent(restart_event) == 0) {
829 "Parent: ResetEvent(restart_event) failed.");
830 }
831 if (SetEvent(child_exit_event) == 0) {
833 "Parent: SetEvent for child process event %pp failed.",
835 }
836 /* Don't wait to verify that the child process really exits,
837 * just move on with the restart.
838 */
841 }
842 else {
843 /* The child process exited prematurely due to a fatal error. */
846 /* HUH? We did exit, didn't we? */
848 }
851 || exitcode == APEXIT_INIT) {
853 "Parent: child process %lu exited with status %lu -- Aborting.",
856 }
857 else {
858 int i;
859 restart_pending = 1;
861 "Parent: child process %lu exited with status %lu -- Restarting.",
863 for (i = 0; i < ap_threads_per_child; i++) {
865 }
866 }
869 }
870
871 winnt_note_child_killed(/* slot */ 0);
872
873 if (restart_pending) {
876 }
877die_now:
879 {
880 int timeout = 30000; /* Timeout is milliseconds */
882
883 if (!child_created) {
884 return 0; /* Tell the caller we do not want to restart */
885 }
886
887 /* This shutdown is only marginally graceful. We will give the
888 * child a bit of time to exit gracefully. If the time expires,
889 * the child will be wacked.
890 */
891 if (!strcasecmp(signal_arg, "runservice")) {
893 }
894 /* Signal the child processes to exit */
895 if (SetEvent(child_exit_event) == 0) {
897 "Parent: SetEvent for child process event %pp failed",
899 }
902 if (rv == WAIT_OBJECT_0) {
904 "Parent: Child process %lu exited successfully.", child_pid);
907 }
908 else {
910 "Parent: Forcing termination of child process %lu",
911 child_pid);
915 }
916 }
918 return 0; /* Tell the caller we do not want to restart */
919 }
922 return 1; /* Tell the caller we want a restart */
923}
924
925/* service_nt_main_fn needs to append the StartService() args
926 * outside of our call stack and thread as the service starts...
927 */
929
930/* Remember service_to_start failures to log and fail in pre_config.
931 * Remember inst_argc and inst_argv for installing or starting the
932 * service after we preflight the config.
933 */
934
935static int winnt_query(int query_code, int *result, apr_status_t *rv)
936{
937 *rv = APR_SUCCESS;
938 switch (query_code) {
941 break;
944 break;
947 break;
950 break;
953 break;
956 break;
958 *result = 0;
959 break;
961 *result = 0;
962 break;
964 *result = 0;
965 break;
967 *result = 0;
968 break;
971 break;
973 *result = 1;
974 break;
977 break;
980 break;
981 default:
982 *rv = APR_ENOTIMPL;
983 break;
984 }
985 return OK;
986}
987
988static const char *winnt_get_name(void)
989{
990 return "WinNT";
991}
992
993#define SERVICE_UNSET (-1)
996static int inst_argc;
997static const char * const *inst_argv;
998static const char *service_name = NULL;
999
1000static void winnt_rewrite_args(process_rec *process)
1001{
1002 /* Handle the following SCM aspects in this phase:
1003 *
1004 * -k runservice [transition in service context only]
1005 * -k install
1006 * -k config
1007 * -k uninstall
1008 * -k stop
1009 * -k shutdown (same as -k stop). Maintained for backward compatibility.
1010 *
1011 * We can't leave this phase until we know our identity
1012 * and modify the command arguments appropriately.
1013 *
1014 * We do not care if the .conf file exists or is parsable when
1015 * attempting to stop or uninstall a service.
1016 */
1017 apr_status_t rv;
1018 char *def_server_root;
1019 char *binpath;
1020 char optbuf[3];
1021 const char *opt_arg;
1022 int fixed_args;
1023 char *pid;
1025 int running_as_service = 1;
1026 int errout = 0;
1028
1029 pconf = process->pconf;
1030
1031 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1033
1034 /* We wish this was *always* a reservation, but sadly it wasn't so and
1035 * we couldn't break a hard limit prior to NT Kernel 5.1
1036 */
1037 if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1038 && ((osver.dwMajorVersion > 5)
1039 || ((osver.dwMajorVersion == 5) && (osver.dwMinorVersion > 0)))) {
1041 }
1042
1043 /* AP_PARENT_PID is only valid in the child */
1044 pid = getenv("AP_PARENT_PID");
1045 if (pid)
1046 {
1047 HANDLE filehand;
1050
1051 /* This is the child */
1053 parent_pid = (DWORD) atol(pid);
1054
1055 /* Prevent holding open the (nonexistent) console */
1057
1058 /* The parent gave us stdin, we need to remember this
1059 * handle, and no longer inherit it at our children
1060 * (we can't slurp it up now, we just aren't ready yet).
1061 * The original handle is closed below, at apr_file_dup2()
1062 */
1064 if (DuplicateHandle(hproc, pipe,
1065 hproc, &filehand, 0, FALSE,
1067 pipe = filehand;
1068 }
1069
1070 /* The parent gave us stdout of the NUL device,
1071 * and expects us to suck up stdin of all of our
1072 * shared handles and data from the parent.
1073 * Don't infect child processes with our stdin
1074 * handle, use another handle to NUL!
1075 */
1076 {
1078 if ((apr_file_open_stdout(&outfile, process->pool) == APR_SUCCESS)
1079 && (apr_file_open_stdin(&infile, process->pool) == APR_SUCCESS))
1080 apr_file_dup2(infile, outfile, process->pool);
1081 }
1082
1083 /* This child needs the existing stderr opened for logging,
1084 * already
1085 */
1086
1087 /* Read this child's generation number as soon as now,
1088 * so that further hooks can query it.
1089 */
1090 if (!ReadFile(pipe, &my_generation, sizeof(my_generation),
1092 || (BytesRead != sizeof(my_generation))) {
1094 "Child: Unable to retrieve my generation from the parent");
1096 }
1097
1098 /* The parent is responsible for providing the
1099 * COMPLETE ARGUMENTS REQUIRED to the child.
1100 *
1101 * No further argument parsing is needed, but
1102 * for good measure we will provide a simple
1103 * signal string for later testing.
1104 */
1105 signal_arg = "runchild";
1106 return;
1107 }
1108
1109 /* This is the parent, we have a long way to go :-) */
1111
1112 /* This behavior is voided by setting real_exit_code to 0 */
1114
1115 /* Rewrite process->argv[];
1116 *
1117 * strip out -k signal into signal_arg
1118 * strip out -n servicename and set the names
1119 * add default -d serverroot from the path of this executable
1120 *
1121 * The end result will look like:
1122 *
1123 * The invocation command (%0)
1124 * The -d serverroot default from the running executable
1125 * The requested service's (-n) registry ConfigArgs
1126 * The WinNT SCM's StartService() args
1127 */
1128 if ((rv = ap_os_proc_filepath(&binpath, process->pconf))
1129 != APR_SUCCESS) {
1131 "Failed to get the full path of %s", process->argv[0]);
1133 }
1134 /* WARNING: There is an implicit assumption here that the
1135 * executable resides in ServerRoot or ServerRoot\bin
1136 */
1138 if (def_server_root > binpath) {
1139 *(def_server_root - 1) = '\0';
1141 if (!strcasecmp(def_server_root, "bin"))
1142 *(def_server_root - 1) = '\0';
1143 }
1145 APR_FILEPATH_TRUENAME, process->pool);
1146
1147 /* Use process->pool so that the rewritten argv
1148 * lasts for the lifetime of the server process,
1149 * because pconf will be destroyed after the
1150 * initial pre-flight of the config parser.
1151 */
1152 mpm_new_argv = apr_array_make(process->pool, process->argc + 2,
1153 sizeof(const char *));
1154 *(const char **)apr_array_push(mpm_new_argv) = process->argv[0];
1155 *(const char **)apr_array_push(mpm_new_argv) = "-d";
1156 *(const char **)apr_array_push(mpm_new_argv) = def_server_root;
1157
1159
1160 optbuf[0] = '-';
1161 optbuf[2] = '\0';
1162 apr_getopt_init(&opt, process->pool, process->argc, process->argv);
1163 opt->errfn = NULL;
1164 while ((rv = apr_getopt(opt, "wn:k:" AP_SERVER_BASEARGS,
1165 optbuf + 1, &opt_arg)) == APR_SUCCESS) {
1166 switch (optbuf[1]) {
1167
1168 /* Shortcuts; include the -w option to hold the window open on error.
1169 * This must not be toggled once we reset ap_real_exit_code to 0!
1170 */
1171 case 'w':
1174 break;
1175
1176 case 'n':
1178 opt_arg);
1179 break;
1180
1181 case 'k':
1183 break;
1184
1185 case 'E':
1186 errout = 1;
1187 /* Fall through so the Apache main() handles the 'E' arg */
1188 default:
1189 *(const char **)apr_array_push(mpm_new_argv) =
1190 apr_pstrdup(process->pool, optbuf);
1191
1192 if (opt_arg) {
1193 *(const char **)apr_array_push(mpm_new_argv) = opt_arg;
1194 }
1195 break;
1196 }
1197 }
1198
1199 /* back up to capture the bad argument */
1200 if (rv == APR_BADCH || rv == APR_BADARG) {
1201 opt->ind--;
1202 }
1203
1204 while (opt->ind < opt->argc) {
1205 *(const char **)apr_array_push(mpm_new_argv) =
1206 apr_pstrdup(process->pool, opt->argv[opt->ind++]);
1207 }
1208
1209 /* Track the number of args actually entered by the user */
1211
1212 /* Provide a default 'run' -k arg to simplify signal_arg tests */
1213 if (!signal_arg)
1214 {
1215 signal_arg = "run";
1217 }
1218
1219 if (!strcasecmp(signal_arg, "runservice"))
1220 {
1221 /* Start the NT Service _NOW_ because the WinNT SCM is
1222 * expecting us to rapidly assume control of our own
1223 * process, the SCM will tell us our service name, and
1224 * may have extra StartService() command arguments to
1225 * add for us.
1226 *
1227 * The SCM will generally invoke the executable with
1228 * the c:\win\system32 default directory. This is very
1229 * lethal if folks use ServerRoot /foopath on windows
1230 * without a drive letter. Change to the default root
1231 * (path to apache root, above /bin) for safety.
1232 */
1234
1235 /* Any other process has a console, so we don't to begin
1236 * a Win9x service until the configuration is parsed and
1237 * any command line errors are reported.
1238 *
1239 * We hold the return value so that we can die in pre_config
1240 * after logging begins, and the failure can land in the log.
1241 */
1242 if (!errout) {
1244 }
1246 process->pool);
1249 }
1250
1251 /* Open a null handle to soak stdout in this process.
1252 * Windows service processes are missing any file handle
1253 * usable for stdin/out/err. This was the cause of later
1254 * trouble with invocations of apr_file_open_stdout()
1255 */
1256 if ((rv = apr_file_open(&nullfile, "NUL",
1258 process->pool)) == APR_SUCCESS) {
1260 if (apr_file_open_stdout(&nullstdout, process->pool)
1261 == APR_SUCCESS)
1264 }
1265 }
1266
1267 /* Get the default for any -k option, except run */
1268 if (service_set == SERVICE_UNSET && strcasecmp(signal_arg, "run")) {
1271 }
1272
1273 if (!strcasecmp(signal_arg, "install")) /* -k install */
1274 {
1275 if (service_set == APR_SUCCESS)
1276 {
1278 "%s: Service is already installed.", service_name);
1280 }
1281 }
1282 else if (running_as_service)
1283 {
1284 if (service_set == APR_SUCCESS)
1285 {
1286 /* Attempt to Uninstall, or stop, before
1287 * we can read the arguments or .conf files
1288 */
1289 if (!strcasecmp(signal_arg, "uninstall")) {
1290 rv = mpm_service_uninstall();
1291 exit(rv);
1292 }
1293
1294 if ((!strcasecmp(signal_arg, "stop")) ||
1295 (!strcasecmp(signal_arg, "shutdown"))) {
1296 mpm_signal_service(process->pool, 0);
1297 exit(0);
1298 }
1299
1301 fixed_args);
1302 if (rv == APR_SUCCESS) {
1304 "Using ConfigArgs of the installed service "
1305 "\"%s\".", service_name);
1306 }
1307 else {
1309 "No installed ConfigArgs for the service "
1310 "\"%s\", using Apache defaults.", service_name);
1311 }
1312 }
1313 else
1314 {
1316 "No installed service named \"%s\".", service_name);
1318 }
1319 }
1321 {
1323 "No installed service named \"%s\".", service_name);
1325 }
1326
1327 /* Track the args actually entered by the user.
1328 * These will be used for the -k install parameters, as well as
1329 * for the -k start service override arguments.
1330 */
1331 inst_argv = (const char * const *)mpm_new_argv->elts
1333
1334 /* Now, do service install or reconfigure then proceed to
1335 * post_config to test the installed configuration.
1336 */
1337 if (!strcasecmp(signal_arg, "config")) { /* -k config */
1338 /* Reconfigure the service */
1339 rv = mpm_service_install(process->pool, inst_argc, inst_argv, 1);
1340 if (rv != APR_SUCCESS) {
1341 exit(rv);
1342 }
1343
1344 fprintf(stderr,"Testing httpd.conf....\n");
1345 fprintf(stderr,"Errors reported here must be corrected before the "
1346 "service can be started.\n");
1347 }
1348 else if (!strcasecmp(signal_arg, "install")) { /* -k install */
1349 /* Install the service */
1350 rv = mpm_service_install(process->pool, inst_argc, inst_argv, 0);
1351 if (rv != APR_SUCCESS) {
1352 exit(rv);
1353 }
1354
1355 fprintf(stderr,"Testing httpd.conf....\n");
1356 fprintf(stderr,"Errors reported here must be corrected before the "
1357 "service can be started.\n");
1358 }
1359
1360 process->argc = mpm_new_argv->nelts;
1361 process->argv = (const char * const *) mpm_new_argv->elts;
1362}
1363
1364
1366{
1367 /* Handle the following SCM aspects in this phase:
1368 *
1369 * -k runservice [WinNT errors logged from rewrite_args]
1370 */
1371
1372 /* Initialize shared static objects.
1373 * TODO: Put config related statics into an sconf structure.
1374 */
1375 pconf = pconf_;
1376
1377 if (ap_exists_config_define("ONE_PROCESS") ||
1378 ap_exists_config_define("DEBUG"))
1379 one_process = -1;
1380
1381 /* XXX: presume proper privileges; one nice thing would be
1382 * a loud emit if running as "LocalSystem"/"SYSTEM" to indicate
1383 * they should change to a user with write access to logs/ alone.
1384 */
1386
1387 if (!strcasecmp(signal_arg, "runservice")
1390 "%s: Unable to start the service manager.",
1391 service_name);
1393 }
1395 && !one_process && !my_generation) {
1396 /* Open a null handle to soak stdout in this process.
1397 * We need to emulate apr_proc_detach, unix performs this
1398 * same check in the pre_config hook (although it is
1399 * arguably premature). Services already fixed this.
1400 */
1402 apr_status_t rv;
1404
1405 if ((rv = apr_file_open(&nullfile, "NUL",
1407 pproc)) == APR_SUCCESS) {
1410 == APR_SUCCESS)
1413 }
1414 }
1415
1419
1420 return OK;
1421}
1422
1424 apr_pool_t *ptemp, server_rec* s)
1425{
1426 int is_parent;
1427 int startup = 0;
1428
1429 /* We want this only in the parent and only the first time around */
1431 if (is_parent &&
1433 startup = 1;
1434 }
1435
1437 if (startup) {
1439 "WARNING: ThreadLimit of %d exceeds compile-time "
1440 "limit of %d threads, decreasing to %d.",
1442 } else if (is_parent) {
1444 "ThreadLimit of %d exceeds compile-time limit "
1445 "of %d, decreasing to match",
1447 }
1449 }
1450 else if (thread_limit < 1) {
1451 if (startup) {
1453 "WARNING: ThreadLimit of %d not allowed, "
1454 "increasing to 1.", thread_limit);
1455 } else if (is_parent) {
1457 "ThreadLimit of %d not allowed, increasing to 1",
1458 thread_limit);
1459 }
1460 thread_limit = 1;
1461 }
1462
1463 /* You cannot change ThreadLimit across a restart; ignore
1464 * any such attempts.
1465 */
1466 if (!first_thread_limit) {
1467 first_thread_limit = thread_limit;
1468 }
1469 else if (thread_limit != first_thread_limit) {
1470 /* Don't need a startup console version here */
1471 if (is_parent) {
1473 "changing ThreadLimit to %d from original value "
1474 "of %d not allowed during restart",
1475 thread_limit, first_thread_limit);
1476 }
1477 thread_limit = first_thread_limit;
1478 }
1479
1481 if (startup) {
1483 "WARNING: ThreadsPerChild of %d exceeds ThreadLimit "
1484 "of %d threads, decreasing to %d. To increase, please "
1485 "see the ThreadLimit directive.",
1487 } else if (is_parent) {
1489 "ThreadsPerChild of %d exceeds ThreadLimit "
1490 "of %d, decreasing to match",
1492 }
1494 }
1495 else if (ap_threads_per_child < 1) {
1496 if (startup) {
1498 "WARNING: ThreadsPerChild of %d not allowed, "
1499 "increasing to 1.", ap_threads_per_child);
1500 } else if (is_parent) {
1502 "ThreadsPerChild of %d not allowed, increasing to 1",
1504 }
1506 }
1507
1508 return OK;
1509}
1510
1512{
1513 apr_status_t rv = 0;
1514
1515 /* Handle the following SCM aspects in this phase:
1516 *
1517 * -k install (catch and exit as install was handled in rewrite_args)
1518 * -k config (catch and exit as config was handled in rewrite_args)
1519 * -k start
1520 * -k restart
1521 * -k runservice [Win95, only once - after we parsed the config]
1522 *
1523 * because all of these signals are useful _only_ if there
1524 * is a valid conf\httpd.conf environment to start.
1525 *
1526 * We reached this phase by avoiding errors that would cause
1527 * these options to fail unexpectedly in another process.
1528 */
1529
1530 if (!strcasecmp(signal_arg, "install")) {
1531 /* Service install happens in the rewrite_args hooks. If we
1532 * made it this far, the server configuration is clean and the
1533 * service will successfully start.
1534 */
1535 apr_pool_destroy(s->process->pool);
1536 apr_terminate();
1537 exit(0);
1538 }
1539 if (!strcasecmp(signal_arg, "config")) {
1540 /* Service reconfiguration happens in the rewrite_args hooks. If we
1541 * made it this far, the server configuration is clean and the
1542 * service will successfully start.
1543 */
1544 apr_pool_destroy(s->process->pool);
1545 apr_terminate();
1546 exit(0);
1547 }
1548
1549 if (!strcasecmp(signal_arg, "start")) {
1551
1552 /* Close the listening sockets. */
1553 for (lr = ap_listeners; lr; lr = lr->next) {
1554 apr_socket_close(lr->sd);
1555 lr->active = 0;
1556 }
1558 apr_pool_destroy(s->process->pool);
1559 apr_terminate();
1560 exit (rv);
1561 }
1562
1563 if (!strcasecmp(signal_arg, "restart")) {
1564 mpm_signal_service(ptemp, 1);
1565 apr_pool_destroy(s->process->pool);
1566 apr_terminate();
1567 exit (rv);
1568 }
1569
1570 if (parent_pid == my_pid)
1571 {
1574 {
1575 /* This code should be run once in the parent and not run
1576 * across a restart
1577 */
1579
1581
1582 /* Create shutdown event, apPID_shutdown, where PID is the parent
1583 * Apache process ID. Shutdown is signaled by 'apache -k shutdown'.
1584 */
1586 if (!shutdown_event) {
1588 "Parent: Cannot create shutdown event %s", signal_shutdown_name);
1590 }
1591
1592 /* Create restart event, apPID_restart, where PID is the parent
1593 * Apache process ID. Restart is signaled by 'apache -k restart'.
1594 */
1596 if (!restart_event) {
1599 "Parent: Cannot create restart event %s", signal_restart_name);
1601 }
1602
1603 /* Create the start mutex, as an unnamed object for security.
1604 * The start mutex is used during a restart to prevent more than
1605 * one child process from entering the accept loop at once.
1606 */
1610 if (rv != APR_SUCCESS) {
1612 "%s: Unable to create the start_mutex.",
1613 service_name);
1615 }
1616 }
1617 /* Always reset our console handler to be the first, even on a restart
1618 * because some modules (e.g. mod_perl) might have set a console
1619 * handler to terminate the process.
1620 */
1621 if (strcasecmp(signal_arg, "runservice"))
1623 }
1624 else /* parent_pid != my_pid */
1625 {
1627 }
1628 return OK;
1629}
1630
1631/* This really should be a post_config hook, but the error log is already
1632 * redirected by that point, so we need to do this in the open_logs phase.
1633 */
1635{
1636 /* Initialize shared static objects.
1637 */
1638 if (parent_pid != my_pid) {
1639 return OK;
1640 }
1641
1642 /* We cannot initialize our listeners if we are restarting
1643 * (the parent process already has glomed on to them)
1644 * nor should we do so for service reconfiguration
1645 * (since the service may already be running.)
1646 */
1647 if (!strcasecmp(signal_arg, "restart")
1648 || !strcasecmp(signal_arg, "config")) {
1649 return OK;
1650 }
1651
1652 if (ap_setup_listeners(s) < 1) {
1654 NULL, APLOGNO(00451) "no listening sockets available, shutting down");
1655 return !OK;
1656 }
1657
1658 return OK;
1659}
1660
1661static void winnt_child_init(apr_pool_t *pchild, struct server_rec *s)
1662{
1663 apr_status_t rv;
1664
1666
1667 /* This is a child process, not in single process mode */
1668 if (!one_process) {
1669 /* Set up events and the scoreboard */
1672
1673 /* Set up the listeners */
1675
1676 /* Done reading from the parent, close that channel */
1677 CloseHandle(pipe);
1678 }
1679 else {
1680 /* Single process mode - this lock doesn't even need to exist */
1682 APR_LOCK_DEFAULT, s->process->pool);
1683 if (rv != APR_SUCCESS) {
1685 "%s child: Unable to init the start_mutex.",
1686 service_name);
1688 }
1689
1690 /* Borrow the shutdown_even as our _child_ loop exit event */
1692 }
1693}
1694
1695
1697{
1698 static int restart = 0; /* Default is "not a restart" */
1699
1700 /* ### If non-graceful restarts are ever introduced - we need to rerun
1701 * the pre_mpm hook on subsequent non-graceful restarts. But Win32
1702 * has only graceful style restarts - and we need this hook to act
1703 * the same on Win32 as on Unix.
1704 */
1705 if (!restart && ((parent_pid == my_pid) || one_process)) {
1706 /* Set up the scoreboard. */
1707 if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
1708 return !OK;
1709 }
1710 }
1711
1712 if ((parent_pid != my_pid) || one_process)
1713 {
1714 /* The child process or in one_process (debug) mode
1715 */
1717 "Child process is running");
1718
1720
1722 "Child process is exiting");
1723 return DONE;
1724 }
1725 else
1726 {
1727 /* A real-honest to goodness parent */
1729 "%s configured -- resuming normal operations",
1732 "Server built: %s", ap_get_server_built());
1735
1737
1738 if (!restart)
1739 {
1740 /* Shutting down. Clean up... */
1743
1746
1747 return DONE;
1748 }
1749 }
1750
1751 return OK; /* Restart */
1752}
1753
1754static void winnt_hooks(apr_pool_t *p)
1755{
1756 /* Our open_logs hook function must run before the core's, or stderr
1757 * will be redirected to a file, and the messages won't print to the
1758 * console.
1759 */
1760 static const char *const aszSucc[] = {"core.c", NULL};
1761
1770}
1771
1774 winnt_rewrite_args, /* hook to run before apache parses args */
1775 NULL, /* create per-directory config structure */
1776 NULL, /* merge per-directory config structures */
1777 NULL, /* create per-server config structure */
1778 NULL, /* merge per-server config structures */
1779 winnt_cmds, /* command apr_table_t */
1780 winnt_hooks /* register_hooks */
1781};
1782
1783#endif /* def WIN32 */
Symbol export macros and hook functions.
#define AP_DECLARE(type)
Definition ap_config.h:67
Apache Listeners Library.
Apache Multi-Processing Module library.
#define TRUE
Definition abts.h:38
#define FALSE
Definition abts.h:35
APR Atomic Operations.
#define WaitForMultipleObjects(d1, ah, b, d2)
#define SetEvent(h)
#define GetStdHandle(d)
#define GetCurrentProcess()
#define DuplicateHandle(h1, h2, h3, ph4, d1, b, d2)
#define CloseHandle(h)
#define WaitForSingleObject(h, d)
APR Miscellaneous library routines.
APR Command Arguments (getopt)
APR general purpose library routines.
APR Portability Routines.
APR Shared Memory Routines.
APR Strings library.
APR Thread Mutex Routines.
APR Thread and Process Library.
static int one_process
Definition event.c:435
static apr_pool_t * pconf
Definition event.c:441
static void child_main(int child_num_arg, int child_bucket)
Definition event.c:2546
#define DEFAULT_THREAD_LIMIT
Definition event.c:133
static const char * set_thread_limit(cmd_parms *cmd, void *dummy, const char *arg)
Definition event.c:4007
#define MAX_THREAD_LIMIT
Definition event.c:140
static const char * set_threads_per_child(cmd_parms *cmd, void *dummy, const char *arg)
Definition event.c:3985
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
#define AP_DECLARE_MODULE(foo)
void ap_hook_open_logs(ap_HOOK_open_logs_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:163
void ap_hook_check_config(ap_HOOK_check_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:96
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
void ap_hook_child_init(ap_HOOK_child_init_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:167
#define APEXIT_INIT
Definition httpd.h:327
const char * ap_get_server_built(void)
Definition buildmark.c:26
const char * ap_get_server_description(void)
Definition core.c:3587
#define OK
Definition httpd.h:456
#define DONE
Definition httpd.h:458
#define APEXIT_CHILDINIT
Definition httpd.h:329
#define APEXIT_CHILDFATAL
Definition httpd.h:341
#define AP_SQ_MS_CREATE_PRE_CONFIG
Definition http_core.h:1047
int ap_exists_config_define(const char *name)
Definition core.c:2896
int ap_state_query(int query_code)
Definition core.c:5378
#define AP_SQ_RM_NORMAL
Definition http_core.h:1061
#define AP_SQ_MAIN_STATE
Definition http_core.h:1030
#define AP_SQ_RUN_MODE
Definition http_core.h:1032
#define AP_SQ_CONFIG_GEN
Definition http_core.h:1034
#define LISTEN_COMMANDS
Definition ap_listen.h:146
void ap_listen_pre_config(void)
Definition listen.c:804
ap_listen_rec * ap_listeners
Definition listen.c:42
int ap_setup_listeners(server_rec *s)
Definition listen.c:610
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_NOTICE
Definition http_log.h:69
#define APLOG_STARTUP
Definition http_log.h:105
#define APLOG_INFO
Definition http_log.h:70
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
void ap_remove_pid(apr_pool_t *p, const char *fname)
Definition log.c:1611
#define APLOG_ALERT
Definition http_log.h:65
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_EMERG
Definition http_log.h:64
void ap_log_mpm_common(server_rec *s)
Definition log.c:1603
void ap_log_pid(apr_pool_t *p, const char *fname)
Definition log.c:1630
#define APLOG_DEBUG
Definition http_log.h:71
void ap_log_command_line(apr_pool_t *p, server_rec *s)
Definition log.c:1575
#define AP_SERVER_BASEARGS
Definition http_main.h:36
server_rec * ap_server_conf
Definition config.c:62
apr_file_t * infile
Definition util_md5.h:65
void ap_run_child_status(server_rec *s, pid_t pid, ap_generation_t gen, int slot, mpm_child_status state)
Definition mpm_common.c:109
void ap_hook_mpm(ap_HOOK_mpm_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mpm_common.c:97
@ MPM_CHILD_EXITED
Definition ap_mpm.h:207
@ MPM_CHILD_STARTED
Definition ap_mpm.h:206
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define DEFAULT_THREADS_PER_CHILD
Definition mpm_default.h:52
DWORD stack_res_flag
void mpm_start_child_console_handler(void)
Definition service.c:213
apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc, char const *const *argv)
Definition service.c:1035
apr_status_t mpm_service_to_start(const char **display_name, apr_pool_t *p)
Definition service.c:684
apr_status_t mpm_service_set_name(apr_pool_t *p, const char **display_name, const char *set_name)
Definition service.c:561
ap_signal_parent_e
Definition mpm_winnt.h:83
void mpm_nt_eventlog_stderr_open(const char *display_name, apr_pool_t *p)
OSVERSIONINFO osver
void mpm_signal_service(apr_pool_t *ptemp, int signal)
Definition service.c:1147
void hold_console_open_on_error(void)
Definition service.c:111
void mpm_start_console_handler(void)
Definition service.c:206
void ap_signal_parent(ap_signal_parent_e type)
void mpm_service_stopping(void)
Definition service.c:738
DWORD my_pid
apr_status_t mpm_service_uninstall(void)
Definition service.c:946
int winnt_mpm_state
#define AP_DEFAULT_SERVICE_NAME
Definition mpm_winnt.h:36
apr_status_t mpm_service_started(void)
Definition service.c:730
apr_proc_mutex_t * start_mutex
HANDLE exit_event
apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc, char const *const *argv, int reconfig)
Definition service.c:744
apr_status_t mpm_merge_service_args(apr_pool_t *p, apr_array_header_t *args, int fixed_args)
Definition service.c:606
@ SIGNAL_PARENT_SHUTDOWN
Definition mpm_winnt.h:84
@ SIGNAL_PARENT_RESTART_GRACEFUL
Definition mpm_winnt.h:86
@ SIGNAL_PARENT_RESTART
Definition mpm_winnt.h:85
const char * ap_pid_fname
Definition mpm_common.c:150
int ap_sys_privileges_handlers(int inc)
Definition core.c:5062
int ap_max_requests_per_child
Definition mpm_common.c:151
void ap_hook_mpm_get_name(ap_HOOK_mpm_get_name_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mpm_common.c:136
void ap_hook_mpm_query(ap_HOOK_mpm_query_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mpm_common.c:100
#define APR_BADCH
Definition apr_errno.h:457
#define APR_BADARG
Definition apr_errno.h:459
#define APR_ENOTIMPL
Definition apr_errno.h:476
apr_bucket * e
const char *const const char *const * aszSucc
Definition apr_hooks.h:346
#define APR_HOOK_REALLY_FIRST
Definition apr_hooks.h:299
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define RSRC_CONF
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define MPM20_MODULE_STUFF
void * ap_malloc(size_t size) __attribute__((malloc))
Definition util.c:3152
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
#define apr_get_netos_error()
Definition apr_errno.h:1222
#define APR_SUCCESS
Definition apr_errno.h:225
#define apr_get_os_error()
Definition apr_errno.h:1217
int apr_status_t
Definition apr_errno.h:44
int type
#define APR_READ
Definition apr_file_io.h:93
#define APR_WRITE
Definition apr_file_io.h:94
#define APR_OS_DEFAULT
#define APR_FILEPATH_TRUENAME
apr_array_header_t ** result
int strcasecmp(const char *a, const char *b)
char const *const char const *const ** env
apr_int32_t opt
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
int apr_os_sock_t
@ APR_LOCK_DEFAULT
const char * s
Definition apr_strings.h:95
apr_int32_t apr_int32_t apr_int32_t err
const char const char *const const char *const apr_procattr_t * attr
#define APR_FULL_BLOCK
apr_cmdtype_e cmd
const char const char *const * args
#define APR_NO_PIPE
int * exitcode
apr_file_t * child_in
@ APR_PROGRAM
#define AP_MPMQ_IS_FORKED
Definition ap_mpm.h:154
#define AP_MPMQ_MPM_STATE
Definition ap_mpm.h:174
#define AP_MPMQ_MAX_DAEMON_USED
Definition ap_mpm.h:150
#define AP_MPMQ_MAX_SPARE_DAEMONS
Definition ap_mpm.h:166
#define AP_MPMQ_MIN_SPARE_THREADS
Definition ap_mpm.h:164
#define AP_MPMQ_HARD_LIMIT_THREADS
Definition ap_mpm.h:158
#define AP_MPMQ_IS_THREADED
Definition ap_mpm.h:152
#define AP_MPMQ_MAX_THREADS
Definition ap_mpm.h:160
#define AP_MPMQ_MAX_REQUESTS_DAEMON
Definition ap_mpm.h:170
#define AP_MPMQ_MAX_SPARE_THREADS
Definition ap_mpm.h:168
#define AP_MPMQ_GENERATION
Definition ap_mpm.h:178
#define AP_MPMQ_MAX_DAEMONS
Definition ap_mpm.h:172
#define AP_MPMQ_HARD_LIMIT_DAEMONS
Definition ap_mpm.h:156
#define AP_MPMQ_MIN_SPARE_DAEMONS
Definition ap_mpm.h:162
#define AP_MPMQ_STARTING
Definition ap_mpm.h:140
#define AP_MPMQ_RUNNING
Definition ap_mpm.h:141
#define AP_MPMQ_STOPPING
Definition ap_mpm.h:142
#define AP_MPMQ_NOT_SUPPORTED
Definition ap_mpm.h:125
#define AP_MPMQ_STATIC
Definition ap_mpm.h:128
static apr_pool_t * pchild
Definition h2_mplx.c:74
Apache Configuration.
Apache connection library.
CORE HTTP Daemon.
Apache Logging library.
Command line options.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
static pid_t parent_pid
Definition mod_cgid.c:91
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
static int thread_limit
Definition mod_status.c:89
Multi-Processing Modules functions.
static int ap_threads_per_child
static void restart(void)
static int die_now
WinNT MPM specific.
#define HARD_SERVER_LIMIT
Definition mpmt_os2.c:63
static int volatile restart_pending
Definition mpmt_os2.c:86
static int master_main()
Definition mpmt_os2.c:192
static int volatile shutdown_pending
Definition mpmt_os2.c:85
HEV shutdown_event
Apache scoreboard library.
int ap_run_pre_mpm(apr_pool_t *p, ap_scoreboard_e sb_type)
Definition scoreboard.c:102
int ap_generation_t
Definition scoreboard.h:78
scoreboard * ap_scoreboard_image
Definition scoreboard.c:44
void ap_init_scoreboard(void *shared_score)
Definition scoreboard.c:150
apr_status_t ap_reopen_scoreboard(apr_pool_t *p, apr_shm_t **shm, int detached)
Definition scoreboard.c:263
@ SB_SHARED
Definition scoreboard.h:85
#define SERVER_DEAD
Definition scoreboard.h:56
int ap_update_child_status_from_indexes(int child_num, int thread_num, int status, request_rec *r)
Definition scoreboard.c:575
apr_array_header_t * mpm_new_argv
int ap_real_exit_code
Definition service.c:109
Apache's listeners record.
Definition ap_listen.h:47
ap_listen_rec * next
Definition ap_listen.h:51
ap_generation_t running_generation
Definition scoreboard.h:126
A structure that represents one process.
Definition httpd.h:829
int argc
Definition httpd.h:839
apr_pool_t * pool
Definition httpd.h:831
apr_pool_t * pconf
Definition httpd.h:833
const char *const * argv
Definition httpd.h:837
ap_generation_t generation
Definition scoreboard.h:139
process_score * parent
Definition scoreboard.h:162
global_score * global
Definition scoreboard.h:161
A structure to store information for each virtual server.
Definition httpd.h:1322
process_rec * process
Definition httpd.h:1324
apr_status_t apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock)
Definition sockets.c:506
apr_status_t apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, apr_pool_t *cont)
Definition sockets.c:550
apr_status_t apr_socket_close(apr_socket_t *thesocket)
Definition sockets.c:211
IN ULONG IN INT timeout
typedef HANDLE(WINAPI *apr_winapi_fpt_CreateToolhelp32Snapshot)(DWORD dwFlags
typedef DWORD(WINAPI *apr_winapi_fpt_GetCompressedFileSizeA)(IN LPCSTR lpFileName