commit 3e54ac543e934ce2f0b024eb98f2a172a29c5cdf
parent 3e3c0110043bdddbc8678918b556b8439f612ba6
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date: Fri, 26 Dec 2025 13:53:17 +0100
Connection timeouts: get milsec counter only once per round
This lower system load on some platforms (with slow system time
functions). Also this significantly reduce the chance of improper
timeout handling as activity timestamp and time-out checks are now
based on the same value.
Before this commit timeout, the check for timeout could be performed
with notable pause after updating the network activity and a connection
could be marked as "inactive" while it may has actual network activity,
which has not been checked at the "timeout" moment. This became more
important with milliseconds timeout accuracy.
Diffstat:
5 files changed, 65 insertions(+), 8 deletions(-)
diff --git a/src/mhd2/conn_timeout.c b/src/mhd2/conn_timeout.c
@@ -48,13 +48,12 @@
#include "mhd_assert.h"
-#include "mhd_mono_clock.h"
-
#include "mhd_dlinked_list.h"
#include "mhd_daemon.h"
#include "mhd_connection.h"
+#include "daemon_funcs.h"
#include "daemon_logger.h"
#include "conn_timeout.h"
@@ -62,6 +61,7 @@
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
mhd_conn_is_timeout_expired (struct MHD_Connection *restrict c)
{
+ struct MHD_Daemon *const restrict d = c->daemon;
const uint_fast64_t timeout = c->timeout.milsec;
uint_fast64_t now;
uint_fast64_t since_actv;
@@ -71,7 +71,7 @@ mhd_conn_is_timeout_expired (struct MHD_Connection *restrict c)
if (0 == timeout)
return false;
- now = mhd_monotonic_msec_counter (); // TODO: Get and use timer value one time only per round
+ now = mhd_daemon_get_milsec_counter (d);
since_actv = now - c->timeout.last_act;
/* Keep the next lines in sync with #connection_get_wait() to avoid
* undesired side-effects like busy-waiting. */
@@ -87,13 +87,13 @@ mhd_conn_is_timeout_expired (struct MHD_Connection *restrict c)
c->timeout.last_act = now; /* Avoid repetitive messages.
Warn: the order of connections sorted
by timeout is not updated. */
- mhd_LOG_PRINT (c->daemon, MHD_SC_SYS_CLOCK_JUMP_BACK_CORRECTED, \
+ mhd_LOG_PRINT (d, MHD_SC_SYS_CLOCK_JUMP_BACK_CORRECTED, \
mhd_LOG_FMT ("Detected system clock %u " \
"milliseconds jump back."),
(unsigned int) jump_back);
return false;
}
- mhd_LOG_PRINT (c->daemon, MHD_SC_SYS_CLOCK_JUMP_BACK_LARGE, \
+ mhd_LOG_PRINT (d, MHD_SC_SYS_CLOCK_JUMP_BACK_LARGE, \
mhd_LOG_FMT ("Detected too large system clock %" \
PRIuFAST64 " milliseconds jump back"),
jump_back);
@@ -122,7 +122,7 @@ mhd_conn_init_activity_timeout (struct MHD_Connection *restrict c,
if (0u == timeout)
return;
- c->timeout.last_act = mhd_monotonic_msec_counter (); // TODO: Get and use time value one time per round
+ c->timeout.last_act = mhd_daemon_get_milsec_counter (d);
if (mhd_D_HAS_THR_PER_CONN (d))
return;
@@ -194,7 +194,7 @@ mhd_conn_update_activity_mark (struct MHD_Connection *restrict c)
return;
}
- c->timeout.last_act = mhd_monotonic_msec_counter (); // TODO: Get and use time value one time per round
+ c->timeout.last_act = mhd_daemon_get_milsec_counter (d);
if (mhd_D_HAS_THR_PER_CONN (d))
{
mhd_assert (! c->timeout.in_cstm_tmout_list);
diff --git a/src/mhd2/daemon_funcs.c b/src/mhd2/daemon_funcs.c
@@ -52,7 +52,9 @@
#include "mhd_assert.h"
#include "mhd_itc.h"
#include "mhd_daemon.h"
+
#include "daemon_logger.h"
+#include "mhd_mono_clock.h"
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
@@ -271,3 +273,16 @@ mhd_daemon_free_lbuf (struct MHD_Daemon *restrict d,
mhd_daemon_reclaim_lbuf (d, buf->size);
buf->size = 0;
}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ uint_fast64_t
+mhd_daemon_get_milsec_counter (struct MHD_Daemon *restrict d)
+{
+ if (! d->events.time.is_set)
+ {
+ d->events.time.cur = mhd_monotonic_msec_counter ();
+ d->events.time.is_set = true;
+ }
+
+ return d->events.time.cur;
+}
diff --git a/src/mhd2/daemon_funcs.h b/src/mhd2/daemon_funcs.h
@@ -48,7 +48,7 @@
#include "mhd_sys_options.h"
#include "sys_bool_type.h"
-#include "sys_sizet_type.h"
+#include "sys_base_types.h"
struct MHD_Daemon; /* forward declaration */
struct mhd_Buffer; /* forward declaration */
@@ -163,4 +163,13 @@ mhd_daemon_free_lbuf (struct MHD_Daemon *restrict d,
MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (2);
+/**
+ * Get daemon's current value of monotonic milliseconds counter.
+ * @param d the daemon to use
+ */
+MHD_INTERNAL uint_fast64_t
+mhd_daemon_get_milsec_counter (struct MHD_Daemon *restrict d)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
#endif /* ! MHD_DAEMON_FUNCS_H */
diff --git a/src/mhd2/events_process.c b/src/mhd2/events_process.c
@@ -1704,6 +1704,17 @@ get_all_net_updates_by_epoll (struct MHD_Daemon *restrict d)
/**
+ * Prepare daemon's data for the new round of connections processing
+ * @param d the daemon to use
+ */
+static MHD_FN_PAR_NONNULL_ALL_ void
+daemon_reset_per_round_data (struct MHD_Daemon *restrict d)
+{
+ d->events.time.is_set = false;
+}
+
+
+/**
* Perform one round of daemon connection and data processing.
*
* This function do the following:
@@ -1723,6 +1734,8 @@ get_all_net_updates_by_epoll (struct MHD_Daemon *restrict d)
static MHD_FN_PAR_NONNULL_ (1) bool
process_all_events_and_data (struct MHD_Daemon *restrict d)
{
+ daemon_reset_per_round_data (d);
+
switch (d->events.poll_type)
{
case mhd_POLL_TYPE_EXT:
diff --git a/src/mhd2/mhd_daemon.h b/src/mhd2/mhd_daemon.h
@@ -500,6 +500,22 @@ struct mhd_DaemonEventActionRequired
bool resume;
};
+/**
+ * The daemon's time data
+ */
+struct mhd_DaemonEventsCurTime
+{
+ /**
+ * 'true' if @a cur is set
+ */
+ bool is_set;
+ /**
+ * Current value of monotonic milliseconds counter.
+ * Valid only if @a is_set is 'true'.
+ * Updated once per processing round.
+ */
+ uint_fast64_t cur;
+};
/**
* The data for events monitoring
@@ -533,6 +549,10 @@ struct mhd_DaemonEventMonitoringData
*/
mhd_DLNKDL_LIST (MHD_Connection,proc_ready);
+ /**
+ * The daemon's time data
+ */
+ struct mhd_DaemonEventsCurTime time;
};