#include "mpm.h"
#include "mpm_common.h"
-#ifdef DEXTER_MPM
-#define CHILD_INFO_TABLE ap_child_table
-#elif defined(MPMT_PTHREAD_MPM) || defined (PREFORK_MPM)
-#define CHILD_INFO_TABLE ap_scoreboard_image->parent
-#endif
-
+#if HAVE_SYS_TIME_H
+#include <sys/time.h> /* for timeval definitions */
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h> /* for setsockopt prototype */
+#endif
-#ifdef CHILD_INFO_TABLE
+#ifdef MPM_NEEDS_RECLAIM_CHILD_PROCESSES
void ap_reclaim_child_processes(int terminate)
{
- int i, status;
+ int i;
long int waittime = 1024 * 16; /* in usecs */
- struct timeval tv;
- int waitret, tries;
+ apr_status_t waitret;
+ int tries;
int not_dead_yet;
+ int max_daemons = ap_get_max_daemons();
-#ifndef DEXTER_MPM
- ap_sync_scoreboard_image();
-#endif
+ MPM_SYNC_CHILD_TABLE();
for (tries = terminate ? 4 : 1; tries <= 9; ++tries) {
/* don't want to hold up progress any more than
* necessary, but we need to allow children a few moments to exit.
* Set delay with an exponential backoff.
*/
- tv.tv_sec = waittime / 1000000;
- tv.tv_usec = waittime % 1000000;
waittime = waittime * 4;
- ap_select(0, NULL, NULL, NULL, &tv);
+ apr_sleep(waittime);
/* now see who is done */
not_dead_yet = 0;
- for (i = 0; i < ap_max_daemons_limit; ++i) {
- pid_t pid = CHILD_INFO_TABLE[i].pid;
+ for (i = 0; i < max_daemons; ++i) {
+ pid_t pid = MPM_CHILD_PID(i);
+ apr_proc_t proc;
-#ifdef DEXTER_MPM
- if (ap_child_table[i].status == SERVER_DEAD)
-#elif defined(MPMT_PTHREAD_MPM) || defined (PREFORK_MPM)
- if (pid == ap_my_pid || pid == 0)
-#endif
+ if (pid == 0)
continue;
- waitret = waitpid(pid, &status, WNOHANG);
- if (waitret == pid || waitret == -1) {
-#ifdef DEXTER_MPM
- ap_child_table[i].status = SERVER_DEAD;
-#elif defined(MPMT_PTHREAD_MPM) || defined(PREFORK_MPM)
- ap_scoreboard_image->parent[i].pid = 0;
-#endif
+ proc.pid = pid;
+ waitret = apr_wait_proc(&proc, APR_NOWAIT);
+ if (waitret != APR_CHILD_NOTDONE) {
+ MPM_NOTE_CHILD_KILLED(i);
continue;
}
++not_dead_yet;
0, ap_server_conf,
"child process %ld still did not exit, sending a SIGKILL",
(long)pid);
+#ifndef BEOS
kill(pid, SIGKILL);
+#else
+ /* sending a SIGKILL kills the entire team on BeOS, and as
+ * httpd thread is part of that team it removes any chance
+ * of ever doing a restart. To counter this I'm changing to
+ * use a kinder, gentler way of killing a specific thread
+ * that is just as effective.
+ */
+ kill_thread(pid);
+#endif
break;
case 9: /* 14 sec */
/* gave it our best shot, but alas... If this really
break;
}
}
- ap_check_other_child();
+ apr_check_other_child();
if (!not_dead_yet) {
/* nothing left to wait for */
break;
}
}
}
-#endif
+#endif /* NEED_RECLAIM_CHILD_PROCESSES */
/* number of calls to wait_or_timeout between writable probes */
#ifndef INTERVAL_OF_WRITABLE_PROBES
#endif
static int wait_or_timeout_counter;
-void ap_wait_or_timeout(ap_wait_t *status, ap_proc_t *ret, ap_pool_t *p)
+void ap_wait_or_timeout(apr_wait_t *status, apr_proc_t *ret, apr_pool_t *p)
{
- struct timeval tv;
- ap_status_t rv;
+ apr_status_t rv;
++wait_or_timeout_counter;
if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
wait_or_timeout_counter = 0;
-#ifdef APR_HAS_OTHER_CHILD
- ap_probe_writable_fds();
+#if APR_HAS_OTHER_CHILD
+ apr_probe_writable_fds();
#endif
}
- rv = ap_wait_all_procs(ret, status, APR_NOWAIT, p);
- if (ap_canonical_error(rv) == APR_EINTR) {
+ rv = apr_wait_all_procs(ret, status, APR_NOWAIT, p);
+ if (apr_canonical_error(rv) == APR_EINTR) {
ret->pid = -1;
return;
}
return;
}
#endif
- tv.tv_sec = SCOREBOARD_MAINTENANCE_INTERVAL / 1000000;
- tv.tv_usec = SCOREBOARD_MAINTENANCE_INTERVAL % 1000000;
- ap_select(0, NULL, NULL, NULL, &tv);
+ apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL);
ret->pid = -1;
return;
}
+void ap_process_child_status(apr_proc_t *pid, apr_wait_t status)
+{
+ /* Child died... if it died due to a fatal error,
+ * we should simply bail out.
+ */
+ if ((WIFEXITED(status)) &&
+ WEXITSTATUS(status) == APEXIT_CHILDFATAL) {
+ ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, ap_server_conf,
+ "Child %ld returned a Fatal error..." APR_EOL_STR
+ "Apache is exiting!",
+ (long)pid->pid);
+ exit(APEXIT_CHILDFATAL);
+ }
+ if (WIFSIGNALED(status)) {
+ switch (WTERMSIG(status)) {
+ case SIGTERM:
+ case SIGHUP:
+ case SIGUSR1:
+ case SIGKILL:
+ break;
+ default:
+#ifdef SYS_SIGLIST
+#ifdef WCOREDUMP
+ if (WCOREDUMP(status)) {
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
+ 0, ap_server_conf,
+ "child pid %ld exit signal %s (%d), "
+ "possible coredump in %s",
+ (long)pid->pid, (WTERMSIG(status) >= NumSIG) ? "" :
+ SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status),
+ ap_coredump_dir);
+ }
+ else {
+#endif
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
+ 0, ap_server_conf,
+ "child pid %ld exit signal %s (%d)",
+ (long)pid->pid,
+ SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status));
+#ifdef WCOREDUMP
+ }
+#endif
+#else
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
+ 0, ap_server_conf,
+ "child pid %ld exit signal %d",
+ (long)pid->pid, WTERMSIG(status));
+#endif
+ }
+ }
+}
+
+#if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF)
+void ap_sock_disable_nagle(apr_socket_t *s)
+{
+ /* The Nagle algorithm says that we should delay sending partial
+ * packets in hopes of getting more data. We don't want to do
+ * this; we are not telnet. There are bad interactions between
+ * persistent connections and Nagle's algorithm that have very severe
+ * performance penalties. (Failing to disable Nagle is not much of a
+ * problem with simple HTTP.)
+ *
+ * In spite of these problems, failure here is not a shooting offense.
+ */
+ apr_status_t status = apr_setsocketopt(s, APR_TCP_NODELAY, 1);
+ if (status != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, status, ap_server_conf,
+ "setsockopt: (TCP_NODELAY)");
+ }
+}
+#endif