You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by yl...@apache.org on 2018/01/02 16:13:45 UTC

svn commit: r1819855 - /httpd/httpd/trunk/server/mpm/event/event.c

Author: ylavic
Date: Tue Jan  2 16:13:45 2018
New Revision: 1819855

URL: http://svn.apache.org/viewvc?rev=1819855&view=rev
Log:
mpm_event: wakeup the listener to re-enable listening sockets.

When listening sockets are disabled (too many connections) and the number of
workers / active connections comes back below the limit, we need to wake up
the listener to re-enable them.

Add a new connections_above_limit() helper to determine when this applies.


Modified:
    httpd/httpd/trunk/server/mpm/event/event.c

Modified: httpd/httpd/trunk/server/mpm/event/event.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/mpm/event/event.c?rev=1819855&r1=1819854&r2=1819855&view=diff
==============================================================================
--- httpd/httpd/trunk/server/mpm/event/event.c (original)
+++ httpd/httpd/trunk/server/mpm/event/event.c Tue Jan  2 16:13:45 2018
@@ -184,6 +184,7 @@ static volatile int dying = 0;
 static volatile int workers_may_exit = 0;
 static volatile int start_thread_may_exit = 0;
 static volatile int listener_may_exit = 0;
+static volatile int listeners_disabled = 0;
 static int listener_is_wakeable = 0;        /* Pollset supports APR_POLLSET_WAKEABLE */
 static int num_listensocks = 0;
 static apr_int32_t conns_this_child;        /* MaxConnectionsPerChild, only access
@@ -485,6 +486,7 @@ static apr_socket_t **worker_sockets;
 static void disable_listensocks(int process_slot)
 {
     int i;
+    listeners_disabled = 1;
     for (i = 0; i < num_listensocks; i++) {
         apr_pollset_remove(event_pollset, &listener_pollfd[i]);
     }
@@ -497,6 +499,7 @@ static void enable_listensocks(int proce
     if (listener_may_exit) {
         return;
     }
+    listeners_disabled = 0;
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00457)
                  "Accepting new connections again: "
                  "%u active conns (%u lingering/%u clogged/%u suspended), "
@@ -515,6 +518,23 @@ static void enable_listensocks(int proce
     ap_scoreboard_image->parent[process_slot].not_accepting = 0;
 }
 
+static APR_INLINE int connections_above_limit(void)
+{
+    apr_uint32_t i_count = ap_queue_info_get_idlers(worker_queue_info);
+    if (i_count > 0) {
+        apr_uint32_t c_count = apr_atomic_read32(&connection_count);
+        apr_uint32_t l_count = apr_atomic_read32(&lingering_count);
+        if (c_count <= l_count
+                /* Off by 'listeners_disabled' to avoid flip flop */
+                || c_count - l_count < (apr_uint32_t)threads_per_child +
+                                       (i_count - (listeners_disabled != 0)) *
+                                       (worker_factor / WORKER_FACTOR_SCALE)) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
 static void abort_socket_nonblocking(apr_socket_t *csd)
 {
     apr_status_t rv;
@@ -753,6 +773,7 @@ static int child_fatal;
 
 static apr_status_t decrement_connection_count(void *cs_)
 {
+    int is_last_connection;
     event_conn_state_t *cs = cs_;
     switch (cs->pub.state) {
         case CONN_STATE_LINGER_NORMAL:
@@ -765,9 +786,14 @@ static apr_status_t decrement_connection
         default:
             break;
     }
-    /* Unblock the listener if it's waiting for connection_count = 0 */
-    if (!apr_atomic_dec32(&connection_count)
-             && listener_is_wakeable && listener_may_exit) {
+    /* Unblock the listener if it's waiting for connection_count = 0,
+     * or if the listening sockets were disabled due to limits and can
+     * now accept new connections.
+     */
+    is_last_connection = !apr_atomic_dec32(&connection_count);
+    if (listener_is_wakeable
+            && ((is_last_connection && listener_may_exit)
+                || (listeners_disabled && !connections_above_limit()))) {
         apr_pollset_wakeup(event_pollset);
     }
     return APR_SUCCESS;
@@ -1756,7 +1782,7 @@ static void * APR_THREAD_FUNC listener_t
     int process_slot = ti->pslot;
     struct process_score *ps = ap_get_scoreboard_process(process_slot);
     apr_pool_t *tpool = apr_thread_pool_get(thd);
-    int closed = 0, listeners_disabled = 0;
+    int closed = 0;
     int have_idle_worker = 0;
     apr_time_t last_log;
 
@@ -1783,11 +1809,13 @@ static void * APR_THREAD_FUNC listener_t
         timer_event_t *te;
         const apr_pollfd_t *out_pfd;
         apr_int32_t num = 0;
-        apr_uint32_t c_count, l_count, i_count;
         apr_interval_time_t timeout_interval;
         apr_time_t now, timeout_time;
         int workers_were_busy = 0;
 
+        if (conns_this_child <= 0)
+            check_infinite_requests();
+
         if (listener_may_exit) {
             close_listeners(process_slot, &closed);
             if (terminate_mode == ST_UNGRACEFUL
@@ -1795,9 +1823,6 @@ static void * APR_THREAD_FUNC listener_t
                 break;
         }
 
-        if (conns_this_child <= 0)
-            check_infinite_requests();
-
         if (APLOGtrace6(ap_server_conf)) {
             now = apr_time_now();
             /* trace log status every second */
@@ -1895,11 +1920,13 @@ static void * APR_THREAD_FUNC listener_t
         rc = apr_pollset_poll(event_pollset, timeout_interval, &num, &out_pfd);
         if (rc != APR_SUCCESS) {
             if (APR_STATUS_IS_EINTR(rc)) {
-                /* Woken up, if we are exiting we must fall through to kill
-                 * kept-alive connections, otherwise we only need to update
-                 * timeouts (logic is above, so restart the loop).
+                /* Woken up, if we are exiting or listeners are disabled we
+                 * must fall through to kill kept-alive connections or test
+                 * whether listeners should be re-enabled. Otherwise we only
+                 * need to update timeouts (logic is above, so simply restart
+                 * the loop).
                  */
-                if (!listener_may_exit) {
+                if (!listener_may_exit && !listeners_disabled) {
                     continue;
                 }
                 timeout_time = 0;
@@ -1982,26 +2009,17 @@ static void * APR_THREAD_FUNC listener_t
                     ap_assert(0);
                 }
             }
-            else if (pt->type == PT_ACCEPT) {
+            else if (pt->type == PT_ACCEPT && !listeners_disabled) {
                 /* A Listener Socket is ready for an accept() */
                 if (workers_were_busy) {
-                    if (!listeners_disabled)
-                        disable_listensocks(process_slot);
-                    listeners_disabled = 1;
+                    disable_listensocks(process_slot);
                     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
                                  APLOGNO(03268)
                                  "All workers busy, not accepting new conns "
                                  "in this process");
                 }
-                else if ((c_count = apr_atomic_read32(&connection_count))
-                             > (l_count = apr_atomic_read32(&lingering_count))
-                         && (c_count - l_count
-                                > ap_queue_info_get_idlers(worker_queue_info)
-                                  * worker_factor / WORKER_FACTOR_SCALE
-                                  + threads_per_child))
-                {
-                    if (!listeners_disabled)
-                        disable_listensocks(process_slot);
+                else if (connections_above_limit()) {
+                    disable_listensocks(process_slot);
                     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
                                  APLOGNO(03269)
                                  "Too many open connections (%u), "
@@ -2010,13 +2028,9 @@ static void * APR_THREAD_FUNC listener_t
                     ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
                                  "Idle workers: %u",
                                  ap_queue_info_get_idlers(worker_queue_info));
-                    listeners_disabled = 1;
-                }
-                else if (listeners_disabled) {
-                    listeners_disabled = 0;
-                    enable_listensocks(process_slot);
+                    workers_were_busy = 1;
                 }
-                if (!listeners_disabled) {
+                else if (!listener_may_exit) {
                     void *csd = NULL;
                     ap_listen_rec *lr = (ap_listen_rec *) pt->baton;
                     apr_pool_t *ptrans;         /* Pool for per-transaction stuff */
@@ -2174,22 +2188,12 @@ static void * APR_THREAD_FUNC listener_t
             }
         }
 
-        if (listeners_disabled && !workers_were_busy
-            && ((c_count = apr_atomic_read32(&connection_count))
-                    >= (l_count = apr_atomic_read32(&lingering_count))
-                && (i_count = ap_queue_info_get_idlers(worker_queue_info)) > 0
-                && (c_count - l_count
-                        < (i_count - 1) * worker_factor / WORKER_FACTOR_SCALE
-                          + threads_per_child)))
-        {
-            listeners_disabled = 0;
+        if (listeners_disabled
+                && !workers_were_busy
+                && !connections_above_limit()) {
             enable_listensocks(process_slot);
         }
-        /*
-         * XXX: do we need to set some timeout that re-enables the listensocks
-         * XXX: in case no other event occurs?
-         */
-    }     /* listener main loop */
+    } /* listener main loop */
 
     close_listeners(process_slot, &closed);
     ap_queue_term(worker_queue);