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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 /* The purpose of this file is to store the code that MOST mpm's will need
18 * this does not mean a function only goes into this file if every MPM needs
19 * it. It means that if a function is needed by more than one MPM, and
20 * future maintenance would be served by making the code common, then the
21 * function belongs here.
23 * This is going in src/main because it is not platform specific, it is
24 * specific to multi-process servers, but NOT to Unix. Which is why it
25 * does not belong in src/os/unix
29 #include "apr_thread_proc.h"
30 #include "apr_signal.h"
31 #include "apr_strings.h"
32 #define APR_WANT_STRFUNC
34 #include "apr_getopt.h"
35 #include "apr_optional.h"
36 #include "apr_allocator.h"
39 #include "http_config.h"
41 #include "http_main.h"
42 #include "mpm_common.h"
44 #include "ap_listen.h"
45 #include "util_mutex.h"
47 #ifndef AP_MPM_NO_SET_SCOREBOARD
48 #include "scoreboard.h"
61 #if AP_ENABLE_EXCEPTION_HOOK
63 APR_HOOK_LINK(fatal_exception)
64 APR_HOOK_LINK(monitor)
65 APR_HOOK_LINK(drop_privileges)
67 APR_HOOK_LINK(mpm_query)
68 APR_HOOK_LINK(mpm_get_child_pid)
69 APR_HOOK_LINK(mpm_note_child_killed)
70 APR_HOOK_LINK(mpm_register_timed_callback)
72 AP_IMPLEMENT_HOOK_RUN_ALL(int, fatal_exception,
73 (ap_exception_info_t *ei), (ei), OK, DECLINED)
76 APR_HOOK_LINK(monitor)
77 APR_HOOK_LINK(drop_privileges)
79 APR_HOOK_LINK(mpm_query)
80 APR_HOOK_LINK(mpm_get_child_pid)
81 APR_HOOK_LINK(mpm_note_child_killed)
82 APR_HOOK_LINK(mpm_register_timed_callback)
85 AP_IMPLEMENT_HOOK_RUN_ALL(int, monitor,
86 (apr_pool_t *p), (p), OK, DECLINED)
87 AP_IMPLEMENT_HOOK_RUN_ALL(int, drop_privileges,
88 (apr_pool_t * pchild, server_rec * s),
89 (pchild, s), OK, DECLINED)
90 AP_IMPLEMENT_HOOK_RUN_FIRST(int, mpm,
91 (apr_pool_t *pconf, apr_pool_t *plog, server_rec *s),
92 (pconf, plog, s), DECLINED)
93 AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_query,
94 (int query_code, int *result),
95 (query_code, result), APR_ENOTIMPL)
96 AP_IMPLEMENT_HOOK_RUN_FIRST(pid_t, mpm_get_child_pid,
99 AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_note_child_killed,
101 (childnum), APR_ENOTIMPL)
102 AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_timed_callback,
103 (apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton),
104 (t, cbfn, baton), APR_ENOTIMPL)
107 * need better concept for controlling generation of MPM helper functions
108 * Unix MPMs don't have/need mpm.h; currently we rely on non-Unix MPMs providing that file
109 * with AP_MPM_NO_xxx defined for functions that won't work or won't be needed
110 * mpm_common.h has the #if HACK #include "mpm.h"
113 #ifndef AP_MPM_NO_RECLAIM_CHILD_PROCESSES
115 typedef enum {DO_NOTHING, SEND_SIGTERM, SEND_SIGKILL, GIVEUP} action_t;
117 typedef struct extra_process_t {
118 struct extra_process_t *next;
122 static extra_process_t *extras;
124 void ap_register_extra_mpm_process(pid_t pid)
126 extra_process_t *p = (extra_process_t *)malloc(sizeof(extra_process_t));
133 int ap_unregister_extra_mpm_process(pid_t pid)
135 extra_process_t *cur = extras;
136 extra_process_t *prev = NULL;
138 while (cur && cur->pid != pid) {
145 prev->next = cur->next;
151 return 1; /* found */
154 /* we don't know about any such process */
159 static int reclaim_one_pid(pid_t pid, action_t action)
162 apr_status_t waitret;
166 /* Ensure pid sanity. */
172 waitret = apr_proc_wait(&proc, &status, &why, APR_NOWAIT);
173 if (waitret != APR_CHILD_NOTDONE) {
174 #ifndef AP_MPM_NO_PROCESS_CHILD_STATUS
175 if (waitret == APR_CHILD_DONE)
176 ap_process_child_status(&proc, why, status);
186 /* ok, now it's being annoying */
187 ap_log_error(APLOG_MARK, APLOG_WARNING,
189 "child process %" APR_PID_T_FMT
190 " still did not exit, "
197 ap_log_error(APLOG_MARK, APLOG_ERR,
199 "child process %" APR_PID_T_FMT
200 " still did not exit, "
206 /* sending a SIGKILL kills the entire team on BeOS, and as
207 * httpd thread is part of that team it removes any chance
208 * of ever doing a restart. To counter this I'm changing to
209 * use a kinder, gentler way of killing a specific thread
210 * that is just as effective.
217 /* gave it our best shot, but alas... If this really
218 * is a child we are trying to kill and it really hasn't
219 * exited, we will likely fail to bind to the port
222 ap_log_error(APLOG_MARK, APLOG_ERR,
224 "could not make child process %" APR_PID_T_FMT
226 "attempting to continue anyway",
234 void ap_reclaim_child_processes(int terminate)
236 apr_time_t waittime = 1024 * 16;
238 extra_process_t *cur_extra;
241 apr_time_t starttime = apr_time_now();
242 /* this table of actions and elapsed times tells what action is taken
243 * at which elapsed time from starting the reclaim
247 apr_time_t action_time;
249 {DO_NOTHING, 0}, /* dummy entry for iterations where we reap
250 * children but take no action against
253 {SEND_SIGTERM, apr_time_from_sec(3)},
254 {SEND_SIGTERM, apr_time_from_sec(5)},
255 {SEND_SIGTERM, apr_time_from_sec(7)},
256 {SEND_SIGKILL, apr_time_from_sec(9)},
257 {GIVEUP, apr_time_from_sec(10)}
259 int cur_action; /* index of action we decided to take this
262 int next_action = 1; /* index of first real action */
264 ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons);
268 /* don't let waittime get longer than 1 second; otherwise, we don't
269 * react quickly to the last child exiting, and taking action can
272 waittime = waittime * 4;
273 if (waittime > apr_time_from_sec(1)) {
274 waittime = apr_time_from_sec(1);
277 /* see what action to take, if any */
278 if (action_table[next_action].action_time <= apr_time_now() - starttime) {
279 cur_action = next_action;
283 cur_action = 0; /* nothing to do */
286 /* now see who is done */
288 for (i = 0; i < max_daemons; ++i) {
289 pid_t pid = ap_mpm_get_child_pid(i);
292 continue; /* not every scoreboard entry is in use */
295 if (reclaim_one_pid(pid, action_table[cur_action].action)) {
296 ap_mpm_note_child_killed(i);
305 extra_process_t *next = cur_extra->next;
307 if (reclaim_one_pid(cur_extra->pid, action_table[cur_action].action)) {
308 AP_DEBUG_ASSERT(1 == ap_unregister_extra_mpm_process(cur_extra->pid));
315 #if APR_HAS_OTHER_CHILD
316 apr_proc_other_child_refresh_all(APR_OC_REASON_RESTART);
319 } while (not_dead_yet > 0 &&
320 action_table[cur_action].action != GIVEUP);
323 void ap_relieve_child_processes(void)
326 extra_process_t *cur_extra;
329 ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons);
331 /* now see who is done */
332 for (i = 0; i < max_daemons; ++i) {
333 pid_t pid = ap_mpm_get_child_pid(i);
336 continue; /* not every scoreboard entry is in use */
339 if (reclaim_one_pid(pid, DO_NOTHING)) {
340 ap_mpm_note_child_killed(i);
346 extra_process_t *next = cur_extra->next;
348 if (reclaim_one_pid(cur_extra->pid, DO_NOTHING)) {
349 AP_DEBUG_ASSERT(1 == ap_unregister_extra_mpm_process(cur_extra->pid));
355 /* Before sending the signal to the pid this function verifies that
356 * the pid is a member of the current process group; either using
357 * apr_proc_wait(), where waitpid() guarantees to fail for non-child
358 * processes; or by using getpgid() directly, if available. */
359 apr_status_t ap_mpm_safe_kill(pid_t pid, int sig)
367 /* Ensure pid sanity */
373 rv = apr_proc_wait(&proc, &status, &why, APR_NOWAIT);
374 if (rv == APR_CHILD_DONE) {
375 #ifndef AP_MPM_NO_PROCESS_CHILD_STATUS
376 /* The child already died - log the termination status if
378 ap_process_child_status(&proc, why, status);
382 else if (rv != APR_CHILD_NOTDONE) {
383 /* The child is already dead and reaped, or was a bogus pid -
384 * log this either way. */
385 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, ap_server_conf,
386 "cannot send signal %d to pid %ld (non-child or "
387 "already dead)", sig, (long)pid);
393 /* Ensure pid sanity. */
400 /* Process already dead... */
404 if (pg != getpgrp()) {
405 ap_log_error(APLOG_MARK, APLOG_ALERT, 0, ap_server_conf,
406 "refusing to send signal %d to pid %ld outside "
407 "process group", sig, (long)pid);
412 return kill(pid, sig) ? errno : APR_SUCCESS;
414 #endif /* AP_MPM_NO_RECLAIM_CHILD_PROCESSES */
416 #ifndef AP_MPM_NO_WAIT_OR_TIMEOUT
418 /* number of calls to wait_or_timeout between writable probes */
419 #ifndef INTERVAL_OF_WRITABLE_PROBES
420 #define INTERVAL_OF_WRITABLE_PROBES 10
422 static int wait_or_timeout_counter;
424 void ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode, apr_proc_t *ret,
429 ++wait_or_timeout_counter;
430 if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
431 wait_or_timeout_counter = 0;
435 rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p);
436 if (APR_STATUS_IS_EINTR(rv)) {
441 if (APR_STATUS_IS_CHILD_DONE(rv)) {
449 #endif /* AP_MPM_NO_WAIT_OR_TIMEOUT */
451 #ifndef AP_MPM_NO_PROCESS_CHILD_STATUS
452 int ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status)
457 /* Child died... if it died due to a fatal error,
458 * we should simply bail out. The caller needs to
459 * check for bad rc from us and exit, running any
460 * appropriate cleanups.
462 * If the child died due to a resource shortage,
463 * the parent should limit the rate of forking
465 if (APR_PROC_CHECK_EXIT(why)) {
466 if (status == APEXIT_CHILDSICK) {
470 if (status == APEXIT_CHILDFATAL) {
471 ap_log_error(APLOG_MARK, APLOG_ALERT,
473 "Child %" APR_PID_T_FMT
474 " returned a Fatal error... Apache is exiting!",
476 return APEXIT_CHILDFATAL;
482 if (APR_PROC_CHECK_SIGNALED(why)) {
483 sigdesc = apr_signal_description_get(signum);
488 case AP_SIG_GRACEFUL:
493 if (APR_PROC_CHECK_CORE_DUMP(why)) {
494 ap_log_error(APLOG_MARK, APLOG_NOTICE,
496 "child pid %ld exit signal %s (%d), "
497 "possible coredump in %s",
498 (long)pid->pid, sigdesc, signum,
502 ap_log_error(APLOG_MARK, APLOG_NOTICE,
504 "child pid %ld exit signal %s (%d)",
505 (long)pid->pid, sigdesc, signum);
511 #endif /* AP_MPM_NO_PROCESS_CHILD_STATUS */
513 #if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF)
514 void ap_sock_disable_nagle(apr_socket_t *s)
516 /* The Nagle algorithm says that we should delay sending partial
517 * packets in hopes of getting more data. We don't want to do
518 * this; we are not telnet. There are bad interactions between
519 * persistent connections and Nagle's algorithm that have very severe
520 * performance penalties. (Failing to disable Nagle is not much of a
521 * problem with simple HTTP.)
523 * In spite of these problems, failure here is not a shooting offense.
525 apr_status_t status = apr_socket_opt_set(s, APR_TCP_NODELAY, 1);
527 if (status != APR_SUCCESS) {
528 ap_log_error(APLOG_MARK, APLOG_WARNING, status, ap_server_conf,
529 "apr_socket_opt_set: (TCP_NODELAY)");
535 AP_DECLARE(uid_t) ap_uname2id(const char *name)
540 return (atoi(&name[1]));
542 if (!(ent = getpwnam(name))) {
543 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
544 "%s: bad user name %s", ap_server_argv0, name);
548 return (ent->pw_uid);
553 AP_DECLARE(gid_t) ap_gname2id(const char *name)
558 return (atoi(&name[1]));
560 if (!(ent = getgrnam(name))) {
561 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
562 "%s: bad group name %s", ap_server_argv0, name);
566 return (ent->gr_gid);
570 #ifndef HAVE_INITGROUPS
571 int initgroups(const char *name, gid_t basegid)
573 #if defined(QNX) || defined(MPE) || defined(BEOS) || defined(_OSD_POSIX) || defined(TPF) || defined(__TANDEM) || defined(OS2) || defined(WIN32) || defined(NETWARE)
574 /* QNX, MPE and BeOS do not appear to support supplementary groups. */
577 gid_t groups[NGROUPS_MAX];
583 groups[index++] = basegid;
585 while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) {
586 if (g->gr_gid != basegid) {
589 for (names = g->gr_mem; *names != NULL; ++names) {
590 if (!strcmp(*names, name))
591 groups[index++] = g->gr_gid;
598 return setgroups(index, groups);
601 #endif /* def NEED_INITGROUPS */
603 #ifndef AP_MPM_NO_POD
605 AP_DECLARE(apr_status_t) ap_mpm_pod_open(apr_pool_t *p, ap_pod_t **pod)
609 *pod = apr_palloc(p, sizeof(**pod));
610 rv = apr_file_pipe_create_ex(&((*pod)->pod_in), &((*pod)->pod_out),
612 if (rv != APR_SUCCESS) {
616 apr_file_pipe_timeout_set((*pod)->pod_in, 0);
619 /* close these before exec. */
620 apr_file_inherit_unset((*pod)->pod_in);
621 apr_file_inherit_unset((*pod)->pod_out);
626 AP_DECLARE(apr_status_t) ap_mpm_pod_check(ap_pod_t *pod)
632 rv = apr_file_read(pod->pod_in, &c, &len);
634 if ((rv == APR_SUCCESS) && (len == 1)) {
638 if (rv != APR_SUCCESS) {
645 AP_DECLARE(apr_status_t) ap_mpm_pod_close(ap_pod_t *pod)
649 rv = apr_file_close(pod->pod_out);
650 if (rv != APR_SUCCESS) {
654 rv = apr_file_close(pod->pod_in);
655 if (rv != APR_SUCCESS) {
662 static apr_status_t pod_signal_internal(ap_pod_t *pod)
665 char char_of_death = '!';
668 rv = apr_file_write(pod->pod_out, &char_of_death, &one);
669 if (rv != APR_SUCCESS) {
670 ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
671 "write pipe_of_death");
677 /* This function connects to the server, then immediately closes the connection.
678 * This permits the MPM to skip the poll when there is only one listening
679 * socket, because it provides a alternate way to unblock an accept() when
682 static apr_status_t dummy_connection(ap_pod_t *pod)
691 /* create a temporary pool for the socket. pconf stays around too long */
692 rv = apr_pool_create(&p, pod->p);
693 if (rv != APR_SUCCESS) {
697 /* If possible, find a listener which is configured for
698 * plain-HTTP, not SSL; using an SSL port would either be
699 * expensive to do correctly (performing a complete SSL handshake)
700 * or cause log spam by doing incorrectly (simply sending EOF). */
702 while (lp && lp->protocol && strcasecmp(lp->protocol, "http") != 0) {
709 rv = apr_socket_create(&sock, lp->bind_addr->family, SOCK_STREAM, 0, p);
710 if (rv != APR_SUCCESS) {
711 ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
712 "get socket to connect to listener");
717 /* on some platforms (e.g., FreeBSD), the kernel won't accept many
718 * queued connections before it starts blocking local connects...
719 * we need to keep from blocking too long and instead return an error,
720 * because the MPM won't want to hold up a graceful restart for a
723 rv = apr_socket_timeout_set(sock, apr_time_from_sec(3));
724 if (rv != APR_SUCCESS) {
725 ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
726 "set timeout on socket to connect to listener");
727 apr_socket_close(sock);
732 rv = apr_socket_connect(sock, lp->bind_addr);
733 if (rv != APR_SUCCESS) {
734 int log_level = APLOG_WARNING;
736 if (APR_STATUS_IS_TIMEUP(rv)) {
737 /* probably some server processes bailed out already and there
738 * is nobody around to call accept and clear out the kernel
739 * connection queue; usually this is not worth logging
741 log_level = APLOG_DEBUG;
744 ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf,
745 "connect to listener on %pI", lp->bind_addr);
748 /* Create the request string. We include a User-Agent so that
749 * adminstrators can track down the cause of the odd-looking
750 * requests in their logs.
752 srequest = apr_pstrcat(p, "OPTIONS * HTTP/1.0\r\nUser-Agent: ",
753 ap_get_server_banner(),
754 " (internal dummy connection)\r\n\r\n", NULL);
756 /* Since some operating systems support buffering of data or entire
757 * requests in the kernel, we send a simple request, to make sure
758 * the server pops out of a blocking accept().
760 /* XXX: This is HTTP specific. We should look at the Protocol for each
761 * listener, and send the correct type of request to trigger any Accept
764 len = strlen(srequest);
765 apr_socket_send(sock, srequest, &len);
766 apr_socket_close(sock);
772 AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod)
776 rv = pod_signal_internal(pod);
777 if (rv != APR_SUCCESS) {
781 return dummy_connection(pod);
784 void ap_mpm_pod_killpg(ap_pod_t *pod, int num)
787 apr_status_t rv = APR_SUCCESS;
789 /* we don't write anything to the pod here... we assume
790 * that the would-be reader of the pod has another way to
791 * see that it is time to die once we wake it up
793 * writing lots of things to the pod at once is very
794 * problematic... we can fill the kernel pipe buffer and
795 * be blocked until somebody consumes some bytes or
796 * we hit a timeout... if we hit a timeout we can't just
797 * keep trying because maybe we'll never successfully
798 * write again... but then maybe we'll leave would-be
799 * readers stranded (a number of them could be tied up for
800 * a while serving time-consuming requests)
802 for (i = 0; i < num && rv == APR_SUCCESS; i++) {
803 rv = dummy_connection(pod);
806 #endif /* #ifdef AP_MPM_USES_POD */
808 /* standard mpm configuration handling */
809 #ifndef AP_MPM_NO_SET_PIDFILE
810 const char *ap_pid_fname = NULL;
812 const char *ap_mpm_set_pidfile(cmd_parms *cmd, void *dummy,
815 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
820 if (cmd->server->is_virtual) {
821 return "PidFile directive not allowed in <VirtualHost>";
829 #ifndef AP_MPM_NO_SET_SCOREBOARD
830 const char * ap_mpm_set_scoreboard(cmd_parms *cmd, void *dummy,
833 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
838 ap_scoreboard_fname = arg;
843 #ifndef AP_MPM_NO_SET_LOCKFILE
844 const char *ap_lock_fname = NULL;
846 const char *ap_mpm_set_lockfile(cmd_parms *cmd, void *dummy,
849 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
859 #ifndef AP_MPM_NO_SET_MAX_REQUESTS
860 int ap_max_requests_per_child = 0;
862 const char *ap_mpm_set_max_requests(cmd_parms *cmd, void *dummy,
865 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
870 ap_max_requests_per_child = atoi(arg);
876 #ifndef AP_MPM_NO_SET_COREDUMPDIR
877 char ap_coredump_dir[MAX_STRING_LEN];
878 int ap_coredumpdir_configured;
880 const char *ap_mpm_set_coredumpdir(cmd_parms *cmd, void *dummy,
886 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
891 fname = ap_server_root_relative(cmd->pool, arg);
893 return apr_pstrcat(cmd->pool, "Invalid CoreDumpDirectory path ",
896 if ((rv = apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool)) != APR_SUCCESS) {
897 return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
898 " does not exist", NULL);
900 if (finfo.filetype != APR_DIR) {
901 return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
902 " is not a directory", NULL);
904 apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
905 ap_coredumpdir_configured = 1;
910 #ifndef AP_MPM_NO_SET_GRACEFUL_SHUTDOWN
911 int ap_graceful_shutdown_timeout = 0;
913 const char * ap_mpm_set_graceful_shutdown(cmd_parms *cmd, void *dummy,
916 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
920 ap_graceful_shutdown_timeout = atoi(arg);
925 #ifndef AP_MPM_NO_SET_ACCEPT_LOCK_MECH
926 apr_lockmech_e ap_accept_lock_mech = APR_LOCK_DEFAULT;
928 AP_DECLARE(const char *) ap_mpm_set_accept_lock_mech(cmd_parms *cmd,
933 const char *lockfile;
934 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
939 rv = ap_parse_mutex(arg, cmd->server->process->pool,
940 &ap_accept_lock_mech, &lockfile);
942 if ((rv == APR_ENOTIMPL) || (rv == APR_ENOLOCK)) {
943 return apr_pstrcat(cmd->pool, "Invalid AcceptMutex argument ", arg,
944 " (" AP_AVAILABLE_MUTEXES_STRING ")", NULL);
945 } else if (rv == APR_BADARG) {
946 return apr_pstrcat(cmd->pool, "Invalid AcceptMutex filepath ",
950 /* perchild can't use SysV sems because the permissions on the accept
951 * mutex can't be set to allow all processes to use the mutex and
952 * at the same time keep all users from being able to dink with the
955 #if defined(PERCHILD_MPM)
956 if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
957 return apr_pstrcat(cmd->pool, "Invalid AcceptMutex argument ", arg,
958 " (" AP_AVAILABLE_MUTEXES_STRING ")", NULL);
961 if (lockfile && !ap_lock_fname)
962 ap_lock_fname = lockfile;
968 #ifndef AP_MPM_NO_SIGNAL_SERVER
970 static const char *dash_k_arg;
972 static int send_signal(pid_t pid, int sig)
974 if (kill(pid, sig) < 0) {
975 ap_log_error(APLOG_MARK, APLOG_STARTUP, errno, NULL,
976 "sending signal to server");
982 int ap_signal_server(int *exit_status, apr_pool_t *pconf)
987 int have_pid_file = 0;
992 rv = ap_read_pid(pconf, ap_pid_fname, &otherpid);
993 if (rv != APR_SUCCESS) {
994 if (rv != APR_ENOENT) {
995 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, NULL,
996 "Error retrieving pid file %s", ap_pid_fname);
997 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
998 "Remove it before continuing if it is corrupted.");
1002 status = "httpd (no pid file) not running";
1006 if (kill(otherpid, 0) == 0) {
1008 status = apr_psprintf(pconf,
1009 "httpd (pid %" APR_PID_T_FMT ") already "
1010 "running", otherpid);
1013 status = apr_psprintf(pconf,
1014 "httpd (pid %" APR_PID_T_FMT "?) not running",
1019 if (!strcmp(dash_k_arg, "start")) {
1021 printf("%s\n", status);
1026 if (!strcmp(dash_k_arg, "stop")) {
1028 printf("%s\n", status);
1031 send_signal(otherpid, SIGTERM);
1036 if (!strcmp(dash_k_arg, "restart")) {
1038 printf("httpd not running, trying to start\n");
1041 *exit_status = send_signal(otherpid, SIGHUP);
1046 if (!strcmp(dash_k_arg, "graceful")) {
1048 printf("httpd not running, trying to start\n");
1051 *exit_status = send_signal(otherpid, AP_SIG_GRACEFUL);
1056 if (!strcmp(dash_k_arg, "graceful-stop")) {
1057 #ifndef AP_MPM_NO_SET_GRACEFUL_SHUTDOWN
1059 printf("%s\n", status);
1062 *exit_status = send_signal(otherpid, AP_SIG_GRACEFUL_STOP);
1065 printf("httpd MPM \"" MPM_NAME "\" does not support graceful-stop\n");
1073 void ap_mpm_rewrite_args(process_rec *process)
1075 apr_array_header_t *mpm_new_argv;
1082 mpm_new_argv = apr_array_make(process->pool, process->argc,
1083 sizeof(const char **));
1084 *(const char **)apr_array_push(mpm_new_argv) = process->argv[0];
1085 fixed_args = mpm_new_argv->nelts;
1086 apr_getopt_init(&opt, process->pool, process->argc, process->argv);
1089 /* option char returned by apr_getopt() will be stored in optbuf[1] */
1091 while ((rv = apr_getopt(opt, "k:" AP_SERVER_BASEARGS,
1092 optbuf + 1, &optarg)) == APR_SUCCESS) {
1096 if (!strcmp(optarg, "start") || !strcmp(optarg, "stop") ||
1097 !strcmp(optarg, "restart") || !strcmp(optarg, "graceful") ||
1098 !strcmp(optarg, "graceful-stop")) {
1099 dash_k_arg = optarg;
1104 *(const char **)apr_array_push(mpm_new_argv) =
1105 apr_pstrdup(process->pool, optbuf);
1107 *(const char **)apr_array_push(mpm_new_argv) = optarg;
1112 /* back up to capture the bad argument */
1113 if (rv == APR_BADCH || rv == APR_BADARG) {
1117 while (opt->ind < opt->argc) {
1118 *(const char **)apr_array_push(mpm_new_argv) =
1119 apr_pstrdup(process->pool, opt->argv[opt->ind++]);
1122 process->argc = mpm_new_argv->nelts;
1123 process->argv = (const char * const *)mpm_new_argv->elts;
1126 APR_REGISTER_OPTIONAL_FN(ap_signal_server);
1130 #endif /* AP_MPM_NO_SIGNAL_SERVER */
1132 #ifndef AP_MPM_NO_SET_MAX_MEM_FREE
1133 apr_uint32_t ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
1135 const char *ap_mpm_set_max_mem_free(cmd_parms *cmd, void *dummy,
1139 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1144 value = strtol(arg, NULL, 0);
1145 if (value < 0 || errno == ERANGE)
1146 return apr_pstrcat(cmd->pool, "Invalid MaxMemFree value: ",
1149 ap_max_mem_free = (apr_uint32_t)value * 1024;
1154 #endif /* AP_MPM_NO_SET_MAX_MEM_FREE */
1156 #ifndef AP_MPM_NO_SET_STACKSIZE
1157 apr_size_t ap_thread_stacksize = 0; /* use system default */
1159 const char *ap_mpm_set_thread_stacksize(cmd_parms *cmd, void *dummy,
1163 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1168 value = strtol(arg, NULL, 0);
1169 if (value < 0 || errno == ERANGE)
1170 return apr_pstrcat(cmd->pool, "Invalid ThreadStackSize value: ",
1173 ap_thread_stacksize = (apr_size_t)value;
1178 #endif /* AP_MPM_NO_SET_STACKSIZE */
1180 #ifndef AP_MPM_NO_FATAL_SIGNAL_HANDLER
1182 static pid_t parent_pid, my_pid;
1183 static apr_pool_t *pconf;
1185 #if AP_ENABLE_EXCEPTION_HOOK
1187 static int exception_hook_enabled;
1189 const char *ap_mpm_set_exception_hook(cmd_parms *cmd, void *dummy,
1192 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1197 if (cmd->server->is_virtual) {
1198 return "EnableExceptionHook directive not allowed in <VirtualHost>";
1201 if (strcasecmp(arg, "on") == 0) {
1202 exception_hook_enabled = 1;
1204 else if (strcasecmp(arg, "off") == 0) {
1205 exception_hook_enabled = 0;
1208 return "parameter must be 'on' or 'off'";
1214 static void run_fatal_exception_hook(int sig)
1216 ap_exception_info_t ei = {0};
1218 if (exception_hook_enabled &&
1220 my_pid != parent_pid) {
1223 ap_run_fatal_exception(&ei);
1226 #endif /* AP_ENABLE_EXCEPTION_HOOK */
1228 /* handle all varieties of core dumping signals */
1229 static void sig_coredump(int sig)
1231 apr_filepath_set(ap_coredump_dir, pconf);
1232 apr_signal(sig, SIG_DFL);
1233 #if AP_ENABLE_EXCEPTION_HOOK
1234 run_fatal_exception_hook(sig);
1236 /* linuxthreads issue calling getpid() here:
1237 * This comparison won't match if the crashing thread is
1238 * some module's thread that runs in the parent process.
1239 * The fallout, which is limited to linuxthreads:
1240 * The special log message won't be written when such a
1241 * thread in the parent causes the parent to crash.
1243 if (getpid() == parent_pid) {
1244 ap_log_error(APLOG_MARK, APLOG_NOTICE,
1246 "seg fault or similar nasty error detected "
1247 "in the parent process");
1248 /* XXX we can probably add some rudimentary cleanup code here,
1249 * like getting rid of the pid file. If any additional bad stuff
1250 * happens, we are protected from recursive errors taking down the
1251 * system since this function is no longer the signal handler GLA
1254 kill(getpid(), sig);
1255 /* At this point we've got sig blocked, because we're still inside
1256 * the signal handler. When we leave the signal handler it will
1257 * be unblocked, and we'll take the signal... and coredump or whatever
1258 * is appropriate for this particular Unix. In addition the parent
1259 * will see the real signal we received -- whereas if we called
1260 * abort() here, the parent would only see SIGABRT.
1264 apr_status_t ap_fatal_signal_child_setup(server_rec *s)
1270 apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *in_pconf)
1272 #ifndef NO_USE_SIGACTION
1273 struct sigaction sa;
1275 sigemptyset(&sa.sa_mask);
1277 #if defined(SA_ONESHOT)
1278 sa.sa_flags = SA_ONESHOT;
1279 #elif defined(SA_RESETHAND)
1280 sa.sa_flags = SA_RESETHAND;
1285 sa.sa_handler = sig_coredump;
1286 if (sigaction(SIGSEGV, &sa, NULL) < 0)
1287 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGSEGV)");
1289 if (sigaction(SIGBUS, &sa, NULL) < 0)
1290 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGBUS)");
1293 if (sigaction(SIGABORT, &sa, NULL) < 0)
1294 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGABORT)");
1297 if (sigaction(SIGABRT, &sa, NULL) < 0)
1298 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGABRT)");
1301 if (sigaction(SIGILL, &sa, NULL) < 0)
1302 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGILL)");
1305 if (sigaction(SIGFPE, &sa, NULL) < 0)
1306 ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGFPE)");
1309 #else /* NO_USE_SIGACTION */
1311 apr_signal(SIGSEGV, sig_coredump);
1313 apr_signal(SIGBUS, sig_coredump);
1316 apr_signal(SIGABORT, sig_coredump);
1317 #endif /* SIGABORT */
1319 apr_signal(SIGABRT, sig_coredump);
1320 #endif /* SIGABRT */
1322 apr_signal(SIGILL, sig_coredump);
1325 apr_signal(SIGFPE, sig_coredump);
1328 #endif /* NO_USE_SIGACTION */
1331 parent_pid = my_pid = getpid();
1336 #endif /* AP_MPM_NO_FATAL_SIGNAL_HANDLER */
1338 AP_DECLARE(int) ap_mpm_run(apr_pool_t *pconf, apr_pool_t *plog, server_rec *server_conf)
1340 return ap_run_mpm(pconf, plog, server_conf);
1343 AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
1345 return ap_run_mpm_query(query_code, result);
1348 AP_DECLARE(pid_t) ap_mpm_get_child_pid(int childnum)
1350 return ap_run_mpm_get_child_pid(childnum);
1353 AP_DECLARE(apr_status_t) ap_mpm_note_child_killed(int childnum)
1355 return ap_run_mpm_note_child_killed(childnum);
1358 AP_DECLARE(apr_status_t) ap_mpm_register_timed_callback(apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton)
1360 return ap_run_mpm_register_timed_callback(t, cbfn, baton);
1363 AP_DECLARE(const char *)ap_show_mpm(void)