[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libmicrohttpd] branch master updated: Switched internal timers to milli
From: |
gnunet |
Subject: |
[libmicrohttpd] branch master updated: Switched internal timers to milliseconds resolutions. |
Date: |
Mon, 30 Aug 2021 20:21:13 +0200 |
This is an automated email from the git hooks/post-receive script.
karlson2k pushed a commit to branch master
in repository libmicrohttpd.
The following commit(s) were added to refs/heads/master by this push:
new e42ec8f5 Switched internal timers to milliseconds resolutions.
e42ec8f5 is described below
commit e42ec8f54d28c982307367c483cee34ade5c54f8
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
AuthorDate: Mon Aug 30 21:13:54 2021 +0300
Switched internal timers to milliseconds resolutions.
This is needed to handle connection timeouts precisely.
* Fixed connections expired "just before or after" required timeout
* Fixed busy-waiting with low-resolution system timers when connection is
about to timeout. Now low-resolution timers are handled automatically.
* Added log message if application tries to set ridiculously large timeout
---
src/include/microhttpd.h | 6 +-
src/microhttpd/connection.c | 50 ++++++++++-----
src/microhttpd/daemon.c | 152 +++++++++++++++++++++++++++-----------------
src/microhttpd/internal.h | 25 +++++---
4 files changed, 148 insertions(+), 85 deletions(-)
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index 166e9b47..30ee451f 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -96,7 +96,7 @@ extern "C"
* they are parsed as decimal numbers.
* Example: 0x01093001 = 1.9.30-1.
*/
-#define MHD_VERSION 0x00097310
+#define MHD_VERSION 0x00097311
/* If generic headers don't work on your platform, include headers
which define 'va_list', 'size_t', 'ssize_t', 'intptr_t',
@@ -1432,6 +1432,8 @@ enum MHD_OPTION
* After how many seconds of inactivity should a
* connection automatically be timed out? (followed
* by an `unsigned int`; use zero for no timeout).
+ * Values larger than (UINT64_MAX / 2000 - 1) will
+ * be clipped to this number.
*/
MHD_OPTION_CONNECTION_TIMEOUT = 3,
@@ -4133,6 +4135,8 @@ enum MHD_CONNECTION_OPTION
* zero for no timeout.
* If timeout was set to zero (or unset) before, setup of new value by
* MHD_set_connection_option() will reset timeout timer.
+ * Values larger than (UINT64_MAX / 2000 - 1) will
+ * be clipped to this number.
*/
MHD_CONNECTION_OPTION_TIMEOUT
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index bcb3f934..de81f08a 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -3487,17 +3487,17 @@ MHD_update_last_activity_ (struct MHD_Connection
*connection)
{
struct MHD_Daemon *daemon = connection->daemon;
- if (0 == connection->connection_timeout)
+ if (0 == connection->connection_timeout_ms)
return; /* Skip update of activity for connections
without timeout timer. */
if (connection->suspended)
return; /* no activity on suspended connections */
- connection->last_activity = MHD_monotonic_sec_counter ();
+ connection->last_activity = MHD_monotonic_msec_counter ();
if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
return; /* each connection has personal timeout */
- if (connection->connection_timeout != daemon->connection_timeout)
+ if (connection->connection_timeout_ms != daemon->connection_timeout_ms)
return; /* custom timeout, no need to move it in "normal" DLL */
#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
@@ -4011,7 +4011,7 @@ cleanup_connection (struct MHD_Connection *connection)
{
if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
{
- if (connection->connection_timeout == daemon->connection_timeout)
+ if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
XDLL_remove (daemon->normal_timeout_head,
daemon->normal_timeout_tail,
connection);
@@ -4584,11 +4584,13 @@ MHD_connection_handle_idle (struct MHD_Connection
*connection)
}
if (! connection->suspended)
{
- time_t timeout;
- timeout = connection->connection_timeout;
+ uint64_t timeout;
+ timeout = connection->connection_timeout_ms;
+ /* Keep the next lines in sync with #MHD_get_timeout() to avoid
+ * undesired side-effects like busy-waiting. */
if ( (0 != timeout) &&
- (timeout <= (MHD_monotonic_sec_counter ()
- - connection->last_activity)) )
+ (timeout < (MHD_monotonic_msec_counter ()
+ - connection->last_activity)) )
{
MHD_connection_close_ (connection,
MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
@@ -4719,8 +4721,8 @@ MHD_get_connection_info (struct MHD_Connection
*connection,
connection->suspended_dummy = connection->suspended ? MHD_YES : MHD_NO;
return (const union MHD_ConnectionInfo *) &connection->suspended_dummy;
case MHD_CONNECTION_INFO_CONNECTION_TIMEOUT:
- connection->connection_timeout_dummy = (unsigned
- int)
connection->connection_timeout;
+ connection->connection_timeout_dummy =
+ (unsigned int) connection->connection_timeout_ms * 1000;
return (const union MHD_ConnectionInfo *) &connection->
connection_timeout_dummy;
case MHD_CONNECTION_INFO_REQUEST_HEADER_SIZE:
@@ -4759,15 +4761,15 @@ MHD_set_connection_option (struct MHD_Connection
*connection,
switch (option)
{
case MHD_CONNECTION_OPTION_TIMEOUT:
- if (0 == connection->connection_timeout)
- connection->last_activity = MHD_monotonic_sec_counter ();
+ if (0 == connection->connection_timeout_ms)
+ connection->last_activity = MHD_monotonic_msec_counter ();
#if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
#endif
if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
(! connection->suspended) )
{
- if (connection->connection_timeout == daemon->connection_timeout)
+ if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
XDLL_remove (daemon->normal_timeout_head,
daemon->normal_timeout_tail,
connection);
@@ -4777,13 +4779,29 @@ MHD_set_connection_option (struct MHD_Connection
*connection,
connection);
}
va_start (ap, option);
- connection->connection_timeout = va_arg (ap,
- unsigned int);
+ connection->connection_timeout_ms = va_arg (ap,
+ unsigned int);
va_end (ap);
+#if (0 == (UINT64_MAX + 0)) || ((UINT_MAX + 0) >= (UINT64_MAX + 0))
+ if ((UINT64_MAX / 2000 - 1) < connection->connection_timeout_ms)
+ {
+#ifdef HAVE_MESSAGES
+ MHD_DLOG (connection->daemon,
+ _ ("The specified connection timeout (" PRIu64 ") is too " \
+ "large. Maximum allowed value (" PRIu64 ") will be used " \
+ "instead.\n"),
+ connection->connection_timeout_ms,
+ (UINT64_MAX / 2000 - 1));
+#endif
+ connection->connection_timeout_ms = UINT64_MAX / 2000 - 1;
+ }
+ else
+#endif /* UINTMAX_MAX >= UINT64_MAX */
+ connection->connection_timeout_ms *= 1000;
if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
(! connection->suspended) )
{
- if (connection->connection_timeout == daemon->connection_timeout)
+ if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
XDLL_insert (daemon->normal_timeout_head,
daemon->normal_timeout_tail,
connection);
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index d4fd0d6a..090d39d4 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -1869,7 +1869,6 @@ thread_main_handle_connection (void *data)
MHD_socket maxsock;
struct timeval tv;
struct timeval *tvp;
- time_t now;
#if WINDOWS
#ifdef HAVE_POLL
int extra_slot;
@@ -1893,7 +1892,7 @@ thread_main_handle_connection (void *data)
while ( (! daemon->shutdown) &&
(MHD_CONNECTION_CLOSED != con->state) )
{
- const time_t timeout = con->connection_timeout;
+ uint64_t timeout = con->connection_timeout_ms;
#ifdef UPGRADE_SUPPORT
struct MHD_UpgradeResponseHandle *const urh = con->urh;
#else /* ! UPGRADE_SUPPORT */
@@ -1989,22 +1988,34 @@ thread_main_handle_connection (void *data)
if ( (NULL == tvp) &&
(timeout > 0) )
{
- now = MHD_monotonic_sec_counter ();
- if (now - con->last_activity > timeout)
+ const uint64_t since_actv = MHD_monotonic_msec_counter ()
+ - con->last_activity;
+ if (since_actv > timeout)
+ {
tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+ else if (since_actv == timeout)
+ {
+ /* Exact match for timeout and time from last activity.
+ * Maybe this is just a precise match or this happens because the timer
+ * resolution is too low.
+ * Set wait time to 0.1 seconds to avoid busy-waiting with low
+ * timer resolution as connection is not yet timed-out */
+ tv.tv_sec = 0;
+ tv.tv_usec = 100 * 1000;
+ }
else
{
- const time_t seconds_left = timeout - (now - con->last_activity);
-#if ! defined(_WIN32) || defined(__CYGWIN__)
- tv.tv_sec = seconds_left;
-#else /* _WIN32 && !__CYGWIN__ */
- if (seconds_left > TIMEVAL_TV_SEC_MAX)
+ const uint64_t mseconds_left = timeout - since_actv;
+#if UINT64_MAX != TIMEVAL_TV_SEC_MAX
+ if (mseconds_left / 1000 > TIMEVAL_TV_SEC_MAX)
tv.tv_sec = TIMEVAL_TV_SEC_MAX;
else
- tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) seconds_left;
-#endif /* _WIN32 && ! __CYGWIN__ */
+ tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) mseconds_left / 1000;
+#endif /* UINT64_MAX != TIMEVAL_TV_SEC_MAX */
+ tv.tv_usec = (mseconds_left % 1000) * 1000;
}
- tv.tv_usec = 0;
tvp = &tv;
}
if (! use_poll)
@@ -2474,7 +2485,6 @@ new_connection_prepare_ (struct MHD_Daemon *daemon,
connection->sk_nodelay = _MHD_UNKNOWN;
}
- connection->connection_timeout = daemon->connection_timeout;
if (NULL == (connection->addr = malloc (addrlen)))
{
eno = errno;
@@ -2500,7 +2510,9 @@ new_connection_prepare_ (struct MHD_Daemon *daemon,
connection->is_nonip = sk_is_nonip;
connection->sk_spipe_suppress = sk_spipe_supprs;
connection->daemon = daemon;
- connection->last_activity = MHD_monotonic_sec_counter ();
+ connection->connection_timeout_ms = daemon->connection_timeout_ms;
+ if (0 != connection->connection_timeout_ms)
+ connection->last_activity = MHD_monotonic_msec_counter ();
if (0 == (daemon->options & MHD_USE_TLS))
{
@@ -3061,7 +3073,7 @@ internal_suspend_connection_ (struct MHD_Connection
*connection)
}
if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
{
- if (connection->connection_timeout == daemon->connection_timeout)
+ if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
XDLL_remove (daemon->normal_timeout_head,
daemon->normal_timeout_tail,
connection);
@@ -3270,10 +3282,10 @@ resume_suspended_connections (struct MHD_Daemon *daemon)
if (! used_thr_p_c)
{
/* Reset timeout timer on resume. */
- if (0 != pos->connection_timeout)
- pos->last_activity = MHD_monotonic_sec_counter ();
+ if (0 != pos->connection_timeout_ms)
+ pos->last_activity = MHD_monotonic_msec_counter ();
- if (pos->connection_timeout == daemon->connection_timeout)
+ if (pos->connection_timeout_ms == daemon->connection_timeout_ms)
XDLL_insert (daemon->normal_timeout_head,
daemon->normal_timeout_tail,
pos);
@@ -3824,10 +3836,9 @@ enum MHD_Result
MHD_get_timeout (struct MHD_Daemon *daemon,
MHD_UNSIGNED_LONG_LONG *timeout)
{
- time_t earliest_deadline;
- time_t now;
+ uint64_t earliest_deadline;
struct MHD_Connection *pos;
- bool have_timeout;
+ struct MHD_Connection *earliest_tmot_conn; /**< the connection with earliest
timeout */
#ifdef MHD_USE_THREADS
mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
@@ -3862,44 +3873,63 @@ MHD_get_timeout (struct MHD_Daemon *daemon,
}
#endif /* EPOLL_SUPPORT */
- have_timeout = false;
- earliest_deadline = 0; /* avoid compiler warnings */
- for (pos = daemon->manual_timeout_tail; NULL != pos; pos = pos->prevX)
- {
- if (0 != pos->connection_timeout)
- {
- if ( (! have_timeout) ||
- (earliest_deadline - pos->last_activity > pos->connection_timeout) )
- earliest_deadline = pos->last_activity + pos->connection_timeout;
- have_timeout = true;
- }
- }
+ earliest_tmot_conn = NULL;
+ earliest_deadline = 0; /* mute compiler warning */
/* normal timeouts are sorted, so we only need to look at the 'tail'
(oldest) */
pos = daemon->normal_timeout_tail;
if ( (NULL != pos) &&
- (0 != pos->connection_timeout) )
+ (0 != pos->connection_timeout_ms) )
{
- if ( (! have_timeout) ||
- (earliest_deadline - pos->connection_timeout > pos->last_activity) )
- earliest_deadline = pos->last_activity + pos->connection_timeout;
- have_timeout = true;
+ earliest_tmot_conn = pos;
+ earliest_deadline = pos->last_activity + pos->connection_timeout_ms;
}
- if (! have_timeout)
- return MHD_NO;
- now = MHD_monotonic_sec_counter ();
- if (earliest_deadline < now)
- *timeout = 0;
- else
+ for (pos = daemon->manual_timeout_tail; NULL != pos; pos = pos->prevX)
{
- const time_t second_left = earliest_deadline - now;
+ if (0 != pos->connection_timeout_ms)
+ {
+ if ( (NULL == earliest_tmot_conn) ||
+ (earliest_deadline - pos->last_activity >
+ pos->connection_timeout_ms) )
+ {
+ earliest_tmot_conn = pos;
+ earliest_deadline = pos->last_activity + pos->connection_timeout_ms;
+ }
+ }
+ }
- if (((unsigned long long) second_left) > ULLONG_MAX / 1000)
- *timeout = ULLONG_MAX;
+ if (NULL != earliest_tmot_conn)
+ {
+ const uint64_t since_actv = MHD_monotonic_msec_counter ()
+ - earliest_tmot_conn->last_activity;
+ /* Keep the next lines in sync with #MHD_connection_handle_idle() and
+ * with #thread_main_handle_connection(). */
+ if (since_actv > earliest_tmot_conn->connection_timeout_ms)
+ *timeout = 0;
+ else if (since_actv == earliest_tmot_conn->connection_timeout_ms)
+ {
+ /* Exact match for timeout and time from last activity.
+ * Maybe this is just a precise match or this happens because the timer
+ * resolution is too low.
+ * Set wait time to 0.1 seconds to avoid busy-waiting with low
+ * timer resolution as connection is not yet timed-out */
+ *timeout = 100;
+ }
else
- *timeout = 1000LLU * (unsigned long long) second_left;
+ {
+ const uint64_t mssecond_left = earliest_tmot_conn->connection_timeout_ms
+ - since_actv;
+
+#if UINT64_MAX != ULLONG_MAX
+ if (mssecond_left > ULLONG_MAX)
+ *timeout = ULLONG_MAX;
+ else
+#endif /* UINT64 != ULLONG_MAX */
+ *timeout = (unsigned long long) mssecond_left;
+ }
+ return MHD_YES;
}
- return MHD_YES;
+ return MHD_NO;
}
@@ -5247,7 +5277,7 @@ close_connection (struct MHD_Connection *pos)
#endif
mhd_assert (! pos->suspended);
mhd_assert (! pos->resuming);
- if (pos->connection_timeout == daemon->connection_timeout)
+ if (pos->connection_timeout_ms == daemon->connection_timeout_ms)
XDLL_remove (daemon->normal_timeout_head,
daemon->normal_timeout_tail,
pos);
@@ -5593,20 +5623,22 @@ parse_options_va (struct MHD_Daemon *daemon,
case MHD_OPTION_CONNECTION_TIMEOUT:
uv = va_arg (ap,
unsigned int);
- daemon->connection_timeout = (time_t) uv;
- /* Next comparison could be always false on some platforms and whole
branch will
- * be optimized out on those platforms. On others it will be compiled
into real
- * check. */
- if ( ( (MHD_TYPE_IS_SIGNED_ (time_t)) &&
- (daemon->connection_timeout < 0) ) || /* Compiler may warn on
some platforms, ignore warning. */
- (uv != (unsigned int) daemon->connection_timeout) )
+#if (0 == (UINT64_MAX + 0)) || ((UINT_MAX + 0) >= (UINT64_MAX + 0))
+ if ((UINT64_MAX / 2000 - 1) < uv)
{
#ifdef HAVE_MESSAGES
MHD_DLOG (daemon,
- _ ("Warning: Too large timeout value, ignored.\n"));
+ _ ("The specified connection timeout (%u) is too large. " \
+ "Maximum allowed value (" PRIu64 ") will be used " \
+ "instead.\n"),
+ uv,
+ (UINT64_MAX / 2000 - 1));
#endif
- daemon->connection_timeout = 0;
+ daemon->connection_timeout_ms = UINT64_MAX / 2000 - 1;
}
+ else
+#endif /* UINTMAX_MAX >= UINT64_MAX */
+ daemon->connection_timeout_ms = uv * 1000;
break;
case MHD_OPTION_NOTIFY_COMPLETED:
daemon->notify_completed = va_arg (ap,
@@ -6444,7 +6476,7 @@ MHD_start_daemon_va (unsigned int flags,
daemon->pool_size = MHD_POOL_SIZE_DEFAULT;
daemon->pool_increment = MHD_BUF_INC_SIZE;
daemon->unescape_callback = &unescape_wrapper;
- daemon->connection_timeout = 0; /* no timeout */
+ daemon->connection_timeout_ms = 0; /* no timeout */
MHD_itc_set_invalid_ (daemon->itc);
#ifdef SOMAXCONN
daemon->listen_backlog_size = SOMAXCONN;
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index 9db32af1..a9f5e141 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -43,6 +43,13 @@
#include <stdbool.h>
#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif /* HAVE_INTTYPES_H */
+
+#ifndef PRIu64
+#define PRIu64 "llu"
+#endif /* ! PRIu64 */
#ifdef MHD_PANIC
/* Override any defined MHD_PANIC macro with proper one */
@@ -1143,13 +1150,14 @@ struct MHD_Connection
* Last time this connection had any activity
* (reading or writing).
*/
- time_t last_activity;
+ uint64_t last_activity;
/**
- * After how many seconds of inactivity should
- * this connection time out? Zero for no timeout.
+ * After how many milliseconds of inactivity should
+ * this connection time out?
+ * Zero for no timeout.
*/
- time_t connection_timeout;
+ uint64_t connection_timeout_ms;
/**
* Special member to be returned by #MHD_get_connection_info()
@@ -1707,7 +1715,7 @@ struct MHD_Daemon
* moved back to the tail of the list.
*
* All connections by default start in this list; if a custom
- * timeout that does not match @e connection_timeout is set, they
+ * timeout that does not match @e connection_timeout_ms is set, they
* are moved to the @e manual_timeout_head-XDLL.
* Not used in MHD_USE_THREAD_PER_CONNECTION mode as each thread
* needs only one connection-specific timeout.
@@ -1968,10 +1976,11 @@ struct MHD_Daemon
unsigned int connection_limit;
/**
- * After how many seconds of inactivity should
- * connections time out? Zero for no timeout.
+ * After how many milliseconds of inactivity should
+ * this connection time out?
+ * Zero for no timeout.
*/
- time_t connection_timeout;
+ uint64_t connection_timeout_ms;
/**
* Maximum number of connections per IP, or 0 for
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [libmicrohttpd] branch master updated: Switched internal timers to milliseconds resolutions.,
gnunet <=