mpm_event: handle lingering close fully in process_lingering_close().

* server/mpm/event/event.c (start_lingering_close_blocking): Axe the function
  and put the code directly in process_lingering_close() on the first call when
  cs->pub.state == CONN_STATE_LINGER, this simplifies lingering close handling
  from process_socket() and event_resume_suspended().

No functional changes.

Follow up to r1891716.
Github: #208


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1891717 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c
index 80fac98..b43b05e 100644
--- a/server/mpm/event/event.c
+++ b/server/mpm/event/event.c
@@ -829,48 +829,6 @@
     ap_run_resume_connection(cs->c, cs->r);
 }
 
-static void close_connection(event_conn_state_t *cs);
-
-/*
- * Close our side of the connection, flushing data to the client first.
- * Pre-condition: cs is not in any timeout queue and not in the pollset,
- *                timeout_mutex is not locked
- * return: 0 if connection is fully closed,
- *         1 if connection is lingering
- * May only be called by worker thread.
- */
-static int start_lingering_close_blocking(event_conn_state_t *cs)
-{
-    apr_socket_t *csd = cs->pfd.desc.s;
-
-    /* defer_lingering_close() may have bumped lingering_count already */
-    if (!cs->deferred_linger) {
-        apr_atomic_inc32(&lingering_count);
-    }
-
-    apr_socket_timeout_set(csd, apr_time_from_sec(SECONDS_TO_LINGER));
-    if (ap_start_lingering_close(cs->c)) {
-        notify_suspend(cs);
-        close_connection(cs);
-        return DONE;
-    }
-
-    cs->queue_timestamp = apr_time_now();
-    /*
-     * If some module requested a shortened waiting period, only wait for
-     * 2s (SECONDS_TO_LINGER). This is useful for mitigating certain
-     * DoS attacks.
-     */
-    if (apr_table_get(cs->c->notes, "short-lingering-close")) {
-        cs->pub.state = CONN_STATE_LINGER_SHORT;
-    }
-    else {
-        cs->pub.state = CONN_STATE_LINGER_NORMAL;
-    }
-    notify_suspend(cs);
-    return OK;
-}
-
 /*
  * Defer flush and close of the connection by adding it to defer_linger_chain,
  * for a worker to grab it and do the job (should that be blocking).
@@ -1279,12 +1237,10 @@
         return;
     }
 
-    if (cs->pub.state == CONN_STATE_LINGER) {
-        rc = start_lingering_close_blocking(cs);
-    }
-    if (rc == OK && (cs->pub.state == CONN_STATE_LINGER_NORMAL ||
-                     cs->pub.state == CONN_STATE_LINGER_SHORT)) {
+    /* CONN_STATE_LINGER[_*] fall through process_lingering_close() */
+    if (cs->pub.state >= CONN_STATE_LINGER) {
         process_lingering_close(cs);
+        return;
     }
 }
 
@@ -1304,14 +1260,7 @@
     apr_atomic_dec32(&suspended_count);
     c->suspended_baton = NULL;
 
-    if (cs->pub.state == CONN_STATE_LINGER) {
-        int rc = start_lingering_close_blocking(cs);
-        if (rc == OK && (cs->pub.state == CONN_STATE_LINGER_NORMAL ||
-                         cs->pub.state == CONN_STATE_LINGER_SHORT)) {
-            process_lingering_close(cs);
-        }
-    }
-    else {
+    if (cs->pub.state < CONN_STATE_LINGER) {
         cs->queue_timestamp = apr_time_now();
         cs->pub.state = CONN_STATE_WRITE_COMPLETION;
         notify_suspend(cs);
@@ -1322,6 +1271,10 @@
         apr_pollset_add(event_pollset, &cs->pfd);
         apr_thread_mutex_unlock(timeout_mutex);
     }
+    else {
+        cs->pub.state = CONN_STATE_LINGER;
+        process_lingering_close(cs);
+    }
 
     return OK;
 }
@@ -1723,6 +1676,34 @@
                   "lingering close from state %i", (int)cs->pub.state);
     AP_DEBUG_ASSERT(cs->pub.state >= CONN_STATE_LINGER);
 
+    if (cs->pub.state == CONN_STATE_LINGER) {
+        /* defer_lingering_close() may have bumped lingering_count already */
+        if (!cs->deferred_linger) {
+            apr_atomic_inc32(&lingering_count);
+        }
+
+        apr_socket_timeout_set(csd, apr_time_from_sec(SECONDS_TO_LINGER));
+        if (ap_start_lingering_close(cs->c)) {
+            notify_suspend(cs);
+            close_connection(cs);
+            return;
+        }
+
+        cs->queue_timestamp = apr_time_now();
+        /*
+         * If some module requested a shortened waiting period, only wait for
+         * 2s (SECONDS_TO_LINGER). This is useful for mitigating certain
+         * DoS attacks.
+         */
+        if (apr_table_get(cs->c->notes, "short-lingering-close")) {
+            cs->pub.state = CONN_STATE_LINGER_SHORT;
+        }
+        else {
+            cs->pub.state = CONN_STATE_LINGER_NORMAL;
+        }
+        notify_suspend(cs);
+    }
+
     apr_socket_timeout_set(csd, 0);
     do {
         nbytes = sizeof(dummybuf);