You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ko...@apache.org on 2017/07/12 16:02:39 UTC

svn commit: r1801747 - in /httpd/httpd/trunk: docs/log-message-tags/next-number server/mpm/winnt/child.c

Author: kotkov
Date: Wed Jul 12 16:02:39 2017
New Revision: 1801747

URL: http://svn.apache.org/viewvc?rev=1801747&view=rev
Log:
mpm_winnt: Tweak the listener shutdown code to use a separate event
instead of the global variable (shutdown_in_progress).

This change has two purposes.  First of all, it makes the listener threads
which are blocked waiting for a completion context exit immediately during
shutdown.  Previously, such threads would only check for exit every second.
The second reason for this change is to put the child_main() function in
charge of controlling the listeners life cycle.  Previously, such relation
was circumvented by the fact that the listeners were also waiting for the
global child exit_event.  With the new separate listener_shutdown_event,
only the child_main() function is responsible for shutting down the
listeners, and I think that this makes the code a bit clearer.

All the original behavior, including the special APLOG_DEBUG diagnostic
message when we fail to acquire a free completion context in 1 second,
is kept unchanged.

Modified:
    httpd/httpd/trunk/docs/log-message-tags/next-number
    httpd/httpd/trunk/server/mpm/winnt/child.c

Modified: httpd/httpd/trunk/docs/log-message-tags/next-number
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/log-message-tags/next-number?rev=1801747&r1=1801746&r2=1801747&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/log-message-tags/next-number (original)
+++ httpd/httpd/trunk/docs/log-message-tags/next-number Wed Jul 12 16:02:39 2017
@@ -1 +1 @@
-10035
+10036

Modified: httpd/httpd/trunk/server/mpm/winnt/child.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/mpm/winnt/child.c?rev=1801747&r1=1801746&r2=1801747&view=diff
==============================================================================
--- httpd/httpd/trunk/server/mpm/winnt/child.c (original)
+++ httpd/httpd/trunk/server/mpm/winnt/child.c Wed Jul 12 16:02:39 2017
@@ -135,7 +135,7 @@ typedef enum {
 } io_state_e;
 
 static apr_pool_t *pchild;
-static int shutdown_in_progress = 0;
+static HANDLE listener_shutdown_event;
 static int workers_may_exit = 0;
 static HANDLE max_requests_per_child_event;
 
@@ -203,6 +203,7 @@ static apr_status_t mpm_get_completion_c
              */
             if (num_completion_contexts >= max_num_completion_contexts) {
                 DWORD rv;
+                HANDLE events[2];
                 /* All workers are busy, need to wait for one */
                 static int reported = 0;
                 if (!reported) {
@@ -218,26 +219,31 @@ static apr_status_t mpm_get_completion_c
                  * succeeds, get the context off the queue. It must be
                  * available, since there's only one consumer.
                  */
-                rv = WaitForSingleObject(qwait_event, 1000);
-                if (rv == WAIT_OBJECT_0)
+                events[0] = qwait_event;
+                events[1] = listener_shutdown_event;
+                rv = WaitForMultipleObjects(2, events, FALSE, 1000);
+                if (rv == WAIT_OBJECT_0) {
                     continue;
+                }
+                else if (rv == WAIT_OBJECT_0 + 1) {
+                    /* Got the exit event */
+                    return APR_SUCCESS;
+                }
+                else if (rv == WAIT_TIMEOUT) {
+                    /* Workers are busy, write a diagnostic message and retry */
+                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00327)
+                                 "mpm_get_completion_context: Failed to get a "
+                                 "free context within 1 second");
+                    continue;
+                }
                 else {
-                    if (rv == WAIT_TIMEOUT) {
-                        /* somewhat-normal condition where threads are busy */
-                        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00327)
-                                     "mpm_get_completion_context: Failed to get a "
-                                     "free context within 1 second");
-                        return APR_TIMEUP;
-                    }
-                    else {
-                        /* should be the unexpected, generic WAIT_FAILED */
-                        status = APR_FROM_OS_ERROR(rv);
-                        ap_log_error(APLOG_MARK, APLOG_WARNING, status,
-                                     ap_server_conf, APLOGNO(00328)
-                                     "mpm_get_completion_context: "
-                                     "WaitForSingleObject failed to get free context");
-                        return status;
-                    }
+                    /* should be the unexpected, generic WAIT_FAILED */
+                    status = APR_FROM_OS_ERROR(rv);
+                    ap_log_error(APLOG_MARK, APLOG_WARNING, status,
+                                 ap_server_conf, APLOGNO(00328)
+                                 "mpm_get_completion_context: "
+                                 "WaitForSingleObject failed to get free context");
+                    return status;
                 }
             } else {
                 /* Allocate another context.
@@ -423,7 +429,7 @@ static unsigned int __stdcall winnt_acce
             return 1;
         }
         /* first, high priority event is an already accepted connection */
-        events[1] = exit_event;
+        events[1] = listener_shutdown_event;
         events[2] = max_requests_per_child_event;
     }
     else /* accf == ACCEPT_FILTER_NONE */
@@ -431,7 +437,7 @@ static unsigned int __stdcall winnt_acce
 reinit: /* target of connect upon too many AcceptEx failures */
 
         /* last, low priority event is a not yet accepted connection */
-        events[0] = exit_event;
+        events[0] = listener_shutdown_event;
         events[1] = max_requests_per_child_event;
         events[2] = CreateEvent(NULL, FALSE, FALSE, NULL);
 
@@ -452,13 +458,16 @@ reinit: /* target of connect upon too ma
                  "Child: Accept thread listening on %pI using AcceptFilter %s",
                  lr->bind_addr, accept_filter_to_string(accf));
 
-    while (!shutdown_in_progress) {
+    while (1) {
         if (!context) {
             rv = mpm_get_completion_context(&context);
-            if (APR_STATUS_IS_TIMEUP(rv)) {
-                continue;
+            if (rv) {
+                /* We have an irrecoverable error, tell the child to die */
+                SetEvent(exit_event);
+                break;
             }
-            else if (rv) {
+            else if (rv == APR_SUCCESS && !context) {
+                /* Normal exit */
                 break;
             }
         }
@@ -579,7 +588,7 @@ reinit: /* target of connect upon too ma
                     }
                 }
                 else {
-                    /* exit_event triggered or event handle was closed */
+                    /* listener_shutdown_event triggered or event handle was closed */
                     closesocket(context->accept_socket);
                     context->accept_socket = INVALID_SOCKET;
                     break;
@@ -632,7 +641,7 @@ reinit: /* target of connect upon too ma
 
             if (rv != WAIT_OBJECT_0 + 2) {
                 /* not FD_ACCEPT;
-                 * exit_event triggered or event handle was closed
+                 * listener_shutdown_event triggered or event handle was closed
                  */
                 break;
             }
@@ -672,10 +681,15 @@ reinit: /* target of connect upon too ma
                         ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, APLOGNO(00345)
                                      "Child: Encountered too many accept() "
                                      "resource faults, aborting.");
+                        /* We have an irrecoverable error, tell the child to die */
+                        SetEvent(exit_event);
                         break;
                     }
                     continue;
                 }
+
+                /* We have an irrecoverable error, tell the child to die */
+                SetEvent(exit_event);
                 break;
             }
             /* Per MSDN, cancel the inherited association of this socket
@@ -730,11 +744,6 @@ reinit: /* target of connect upon too ma
     if (accf == ACCEPT_FILTER_NONE)
         CloseHandle(events[2]);
 
-    if (!shutdown_in_progress) {
-        /* Yow, hit an irrecoverable error! Tell the child to die. */
-        SetEvent(exit_event);
-    }
-
     ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ap_server_conf, APLOGNO(00348)
                  "Child: Accept thread exiting.");
     return 0;
@@ -916,6 +925,13 @@ void child_main(apr_pool_t *pconf, DWORD
     ap_run_child_init(pchild, ap_server_conf);
     ht = apr_hash_make(pchild);
 
+    listener_shutdown_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!listener_shutdown_event) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, APLOGNO(10035)
+                     "Child: Failed to create a listener_shutdown event.");
+        exit(APEXIT_CHILDINIT);
+    }
+
     /* Initialize the child_events */
     max_requests_per_child_event = CreateEvent(NULL, TRUE, FALSE, NULL);
     if (!max_requests_per_child_event) {
@@ -1150,7 +1166,7 @@ void child_main(apr_pool_t *pconf, DWORD
      * but allow the worker threads to continue consuming from
      * the queue of accepted connections.
      */
-    shutdown_in_progress = 1;
+    SetEvent(listener_shutdown_event);
 
     Sleep(1000);