Przeglądaj źródła

implement MHD_resume_suspended_connections_

Christian Grothoff 8 lat temu
rodzic
commit
f4355ac34b

+ 1 - 1
src/lib/connection_add.c

@@ -50,7 +50,7 @@ thread_main_connection_upgrade (struct MHD_Connection *con)
   if ( (NULL != daemon->tls_api) &&
        (MHD_ELS_POLL != daemon->event_loop_syscall) )
     {
-      MHD_daemon_upgrade_connection_with_select (con);
+      MHD_daemon_upgrade_connection_with_select_ (con);
     }
 #ifdef HAVE_POLL
   else if (NULL != daemon->tls_api)

+ 2 - 1
src/lib/daemon_destroy.c

@@ -23,6 +23,7 @@
  * @author Christian Grothoff
  */
 #include "internal.h"
+#include "request_resume.h"
 
 
 /**
@@ -113,7 +114,7 @@ MHD_daemon_destroy (struct MHD_Daemon *daemon)
         {
 	  /* Worker daemon or single daemon with internal thread(s). */
           if (! daemon->disallow_suspend_resume)
-            resume_suspended_connections (daemon);
+            (void) MHD_resume_suspended_connections_ (daemon);
 
 	  /* Separate thread(s) is used for polling sockets. */
 	  if (MHD_ITC_IS_VALID_(daemon->itc))

+ 2 - 1
src/lib/daemon_epoll.c

@@ -24,6 +24,7 @@
  */
 #include "internal.h"
 #include "daemon_epoll.h"
+#include "request_resume.h"
 
 #ifdef EPOLL_SUPPORT
 
@@ -301,7 +302,7 @@ MHD_daemon_epoll_ (struct MHD_Daemon *daemon,
     }
 
   if ( (! daemon->disallow_suspend_resume) &&
-       (MHD_YES == resume_suspended_connections (daemon)) )
+       (MHD_resume_suspended_connections_ (daemon)) )
     may_block = false;
 
   if (may_block)

+ 18 - 2
src/lib/daemon_ip_limit.c

@@ -59,6 +59,22 @@ struct MHD_IPCount
 };
 
 
+/**
+ * Trace up to and return master daemon. If the supplied daemon
+ * is a master, then return the daemon itself.
+ *
+ * @param daemon handle to a daemon
+ * @return master daemon handle
+ */
+static struct MHD_Daemon*
+get_master (struct MHD_Daemon *daemon)
+{
+  while (NULL != daemon->master)
+    daemon = daemon->master;
+  return daemon;
+}
+
+
 /**
  * Lock shared structure for IP connection counts and connection DLLs.
  *
@@ -172,7 +188,7 @@ MHD_ip_limit_add (struct MHD_Daemon *daemon,
   void *node;
   int result;
 
-  daemon = MHD_get_master (daemon);
+  daemon = get_master (daemon);
   /* Ignore if no connection limit assigned */
   if (0 == daemon->ip_connection_limit)
     return MHD_YES;
@@ -238,7 +254,7 @@ MHD_ip_limit_del (struct MHD_Daemon *daemon,
   struct MHD_IPCount *found_key;
   void **nodep;
 
-  daemon = MHD_get_master (daemon);
+  daemon = get_master (daemon);
   /* Ignore if no connection limit assigned */
   if (0 == daemon->ip_connection_limit)
     return;

+ 3 - 2
src/lib/daemon_poll.c

@@ -23,6 +23,7 @@
  */
 #include "internal.h"
 #include "daemon_poll.h"
+#include "request_resume.h"
 
 #ifdef HAVE_POLL
 
@@ -143,7 +144,7 @@ MHD_daemon_poll_all_ (struct MHD_Daemon *daemon,
 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
 
   if ( (! daemon->disallow_suspend_resume) &&
-       (MHD_YES == resume_suspended_connections (daemon)) )
+       (MHD_resume_suspended_connections_ (daemon)) )
     may_block = false;
 
   /* count number of connections and thus determine poll set size */
@@ -385,7 +386,7 @@ MHD_daemon_poll_listen_socket_ (struct MHD_Daemon *daemon,
     }
 
   if (! daemon->disallow_suspend_resume)
-    (void) resume_suspended_connections (daemon);
+    (void) MHD_resume_suspended_connections_ (daemon);
 
   if (! may_block)
     timeout = 0;

+ 5 - 2
src/lib/daemon_select.c

@@ -24,6 +24,8 @@
  */
 #include "internal.h"
 #include "daemon_select.h"
+#include "request_resume.h"
+
 
 /**
  * We defined a macro with the same name as a function we
@@ -595,6 +597,7 @@ enum MHD_StatusCode
 MHD_daemon_run_from_select (struct MHD_Daemon *daemon,
 			    const fd_set *read_fd_set,
 
+			    
 			    const fd_set *write_fd_set,
 			    const fd_set *except_fd_set)
 {
@@ -617,7 +620,7 @@ MHD_daemon_run_from_select (struct MHD_Daemon *daemon,
 
   /* Resuming external connections when using an extern mainloop  */
   if (! daemon->disallow_suspend_resume)
-    resume_suspended_connections (daemon);
+    (void) MHD_resume_suspended_connections_ (daemon);
 
   return internal_run_from_select (daemon,
 				   read_fd_set,
@@ -661,7 +664,7 @@ MHD_daemon_select_ (struct MHD_Daemon *daemon,
   maxsock = MHD_INVALID_SOCKET;
   sc = MHD_SC_OK;
   if ( (! daemon->disallow_suspend_resume) &&
-       (MHD_YES == resume_suspended_connections (daemon)) &&
+       (MHD_resume_suspended_connections_ (daemon)) &&
        (MHD_TM_THREAD_PER_CONNECTION != daemon->threading_model) )
     may_block = MHD_NO;
 

+ 121 - 0
src/lib/request_resume.c

@@ -62,4 +62,125 @@ MHD_request_resume (struct MHD_Request *request)
     }
 }
 
+
+/**
+ * Run through the suspended connections and move any that are no
+ * longer suspended back to the active state.
+ * @remark To be called only from thread that process
+ * daemon's select()/poll()/etc.
+ *
+ * @param daemon daemon context
+ * @return true if a connection was actually resumed
+ */
+bool
+MHD_resume_suspended_connections_ (struct MHD_Daemon *daemon)
+{
+  struct MHD_Connection *pos;
+  struct MHD_Connection *prev = NULL;
+  bool ret;
+  const bool used_thr_p_c = (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model);
+  
+  mhd_assert (NULL == daemon->worker_pool);
+  ret = false;
+  MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
+
+  if (daemon->resuming)
+    {
+      prev = daemon->suspended_connections_tail;
+      /* During shutdown check for resuming is forced. */
+      mhd_assert((NULL != prev) || (daemon->shutdown));
+    }
+
+  daemon->resuming = false;
+
+  while (NULL != (pos = prev))
+    {
+#ifdef UPGRADE_SUPPORT
+      struct MHD_UpgradeResponseHandle * const urh = pos->request.urh;
+#else  /* ! UPGRADE_SUPPORT */
+      static const void * const urh = NULL;
+#endif /* ! UPGRADE_SUPPORT */
+      prev = pos->prev;
+      if ( (! pos->resuming)
+#ifdef UPGRADE_SUPPORT
+          || ( (NULL != urh) &&
+               ( (! urh->was_closed) ||
+                 (! urh->clean_ready) ) )
+#endif /* UPGRADE_SUPPORT */
+         )
+        continue;
+      ret = true;
+      mhd_assert (pos->suspended);
+      DLL_remove (daemon->suspended_connections_head,
+                  daemon->suspended_connections_tail,
+                  pos);
+      pos->suspended = false;
+      if (NULL == urh)
+        {
+          DLL_insert (daemon->connections_head,
+                      daemon->connections_tail,
+                      pos);
+          if (! used_thr_p_c)
+            {
+              /* Reset timeout timer on resume. */
+              if (0 != pos->connection_timeout)
+                pos->last_activity = MHD_monotonic_sec_counter();
+
+              if (pos->connection_timeout == daemon->connection_default_timeout)
+                XDLL_insert (daemon->normal_timeout_head,
+                             daemon->normal_timeout_tail,
+                             pos);
+              else
+                XDLL_insert (daemon->manual_timeout_head,
+                             daemon->manual_timeout_tail,
+                             pos);
+            }
+#ifdef EPOLL_SUPPORT
+          if (MHD_ELS_EPOLL == daemon->event_loop_syscall)
+            {
+              if (0 != (pos->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL))
+                MHD_PANIC ("Resumed connection was already in EREADY set\n");
+              /* we always mark resumed connections as ready, as we
+                 might have missed the edge poll event during suspension */
+              EDLL_insert (daemon->eready_head,
+                           daemon->eready_tail,
+                           pos);
+              pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL | \
+                  MHD_EPOLL_STATE_READ_READY | MHD_EPOLL_STATE_WRITE_READY;
+              pos->epoll_state &= ~MHD_EPOLL_STATE_SUSPENDED;
+            }
+#endif
+        }
+#ifdef UPGRADE_SUPPORT
+      else
+        {
+          /* Data forwarding was finished (for TLS connections) AND
+           * application was closed upgraded connection.
+           * Insert connection into cleanup list. */
+          DLL_insert (daemon->cleanup_head,
+                      daemon->cleanup_tail,
+                      pos);
+
+        }
+#endif /* UPGRADE_SUPPORT */
+      pos->resuming = false;
+    }
+  MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
+  if ( (used_thr_p_c) &&
+       (ret) )
+    { /* Wake up suspended connections. */
+      if (! MHD_itc_activate_(daemon->itc,
+                              "w"))
+	{
+#ifdef HAVE_MESSAGES
+	  MHD_DLOG (daemon,
+		    MHD_SC_ITC_USE_FAILED,
+		    _("Failed to signal resume of connection via inter-thread communication channel."));
+#endif
+	}
+    }
+  return ret;
+}
+
+
 /* end of request_resume.c */

+ 43 - 0
src/lib/request_resume.h

@@ -0,0 +1,43 @@
+/*
+  This file is part of libmicrohttpd
+  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/**
+ * @file lib/request_resume.h
+ * @brief implementation of MHD_request_resume()
+ * @author Christian Grothoff
+ */
+
+
+#ifndef REQUEST_RESUME_H
+#define REQUEST_RESUME_H
+
+/**
+ * Run through the suspended connections and move any that are no
+ * longer suspended back to the active state.
+ * @remark To be called only from thread that process
+ * daemon's select()/poll()/etc.
+ *
+ * @param daemon daemon context
+ * @return true if a connection was actually resumed
+ */
+bool
+MHD_resume_suspended_connections_ (struct MHD_Daemon *daemon)
+  MHD_NONNULL(1);
+
+#endif