commit f4355ac34bb1fad42ccb650038bddddb65d70443
parent 5c8fbeb97b01f8d4bb25a01e8ad70ebcd95bb822
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 15 Feb 2018 07:49:56 +0100
implement MHD_resume_suspended_connections_
Diffstat:
8 files changed, 195 insertions(+), 9 deletions(-)
diff --git a/src/lib/connection_add.c b/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)
diff --git a/src/lib/daemon_destroy.c b/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))
diff --git a/src/lib/daemon_epoll.c b/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)
diff --git a/src/lib/daemon_ip_limit.c b/src/lib/daemon_ip_limit.c
@@ -60,6 +60,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.
*
* @param daemon handle to daemon where lock is
@@ -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;
diff --git a/src/lib/daemon_poll.c b/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;
diff --git a/src/lib/daemon_select.c b/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;
diff --git a/src/lib/request_resume.c b/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 */
diff --git a/src/lib/request_resume.h b/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