]> granicus.if.org Git - apache/blobdiff - server/mpm_common.c
APRize disabling nagle (setting TCP_NODELAY).
[apache] / server / mpm_common.c
index cd2f54c69dd8f7e0a3fecc7eac92a3ae71219ab9..d77c66244092a3e3604a98939c916b26fc81f134 100644 (file)
 #if HAVE_SYS_TIME_H
 #include <sys/time.h> /* for timeval definitions */
 #endif
-#ifdef BEOS_BONE
-#include <sys/socket.h>
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h> /* for setsockopt prototype */
 #endif
 
-#if defined(DEXTER_MPM) || defined(MPMT_BEOS_MPM) || defined(MPM_BEOS)
-#define CHILD_TABLE 1
-#define CHILD_INFO_TABLE     ap_child_table
-#elif defined(MPMT_PTHREAD_MPM) || defined (PREFORK_MPM)
-#define SCOREBOARD 1
-#define CHILD_INFO_TABLE     ap_scoreboard_image->parent
-#endif 
-
-
-#ifdef CHILD_INFO_TABLE
+#ifdef MPM_NEEDS_RECLAIM_CHILD_PROCESSES
 void ap_reclaim_child_processes(int terminate)
 {
     int i;
     long int waittime = 1024 * 16;      /* in usecs */
-    struct timeval tv;
-    ap_status_t waitret;
+    apr_status_t waitret;
     int tries;
     int not_dead_yet;
+    int max_daemons = ap_get_max_daemons();
 
-#ifdef SCOREBOARD
-    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;
-            ap_proc_t proc;
+        for (i = 0; i < max_daemons; ++i) {
+            pid_t pid = MPM_CHILD_PID(i);
+            apr_proc_t proc;
 
-#ifdef CHILD_TABLE
-            if (ap_child_table[i].status == SERVER_DEAD)
-#elif defined(SCOREBOARD)
-            if (pid == ap_my_pid || pid == 0)
-#endif
+            if (pid == 0)
                 continue;
 
             proc.pid = pid;
-            waitret = ap_wait_proc(&proc, APR_NOWAIT);
+            waitret = apr_wait_proc(&proc, APR_NOWAIT);
             if (waitret != APR_CHILD_NOTDONE) {
-#ifdef CHILD_TABLE
-                ap_child_table[i].status = SERVER_DEAD;
-#elif defined(SCOREBOARD)
-                ap_scoreboard_image->parent[i].pid = 0;
-#endif
+                MPM_NOTE_CHILD_KILLED(i);
                 continue;
             }
             ++not_dead_yet;
@@ -160,7 +139,17 @@ void ap_reclaim_child_processes(int terminate)
                              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
@@ -175,14 +164,14 @@ void ap_reclaim_child_processes(int terminate)
                 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
@@ -190,20 +179,19 @@ void ap_reclaim_child_processes(int terminate)
 #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;
     }
@@ -215,11 +203,80 @@ void ap_wait_or_timeout(ap_wait_t *status, ap_proc_t *ret, ap_pool_t *p)
         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