Hello! I discovered a problem with closing connections, when MHD_OPTION_CONNECTION_TIMEOUT is used. When I set the timeout option to 3 seconds and connect with a browser, I get a timeout value from MHD_get_timeout() of 3000 ms returned. I then sleep the desired time and call MHD_run again(). Then, MHD_get_timeout() returns repetitive a timeout of 0 which causes thousands of calls to MHD_run(), taking up several hundred milliseconds and burning CPU time.
I use an external event loop with MHD_DAEMON_INFO_EPOLL_FD. As reason I found that the condition timeout < (MHD_monotonic_sec_counter () - connection->last_activity) will not be true, after waiting the timeout time. The right side will be equal to timeout, so the connection is not closed, MHD_get_timeout() continues to return a timeout value of 0, and this runs repetitively in a loop for some thousand iterations, until the time jumps to the next second. In the attachment please find a small patch for fixing this issue. It's just turning the < into a <=. Regards, Alexander Irion ----------------- Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955
From eb6e3c9c7b6c50ac71c2922d95c35f5faeed9b85 Mon Sep 17 00:00:00 2001 From: Alexander Irion <alexander_ir...@mentor.com> Date: Wed, 11 Aug 2021 17:13:12 +0200 Subject: [PATCH] Fix busy waiting up to one second using connection timeout MHD_daemon_get_timeout computes the time to wait as: timeout = (last_activity + connection_timeout - MHD_monotonic_sec_counter ()) * 1000 After sleeping timeout milliseconds, MHD_monotonic_sec_counter () will be: MHD_monotonic_sec_counter () = last_activity + connection_timeout With that (timeout < (MHD_monotonic_sec_counter () - connection->last_activity)) evaluates to false and the MHD_connection_close_ is not done. For the next cycle, MHD_daemon_get_timeout() will return 0 and this goes on, until MHD_monotonic_sec_counter jumps to the next second. This bug causes thousands of unnecessary calls to MHD_run, when a connection timed out. --- src/lib/connection_call_handlers.c | 4 ++-- src/microhttpd/connection.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/connection_call_handlers.c b/src/lib/connection_call_handlers.c index aa082ebb..5f2b9d24 100644 --- a/src/lib/connection_call_handlers.c +++ b/src/lib/connection_call_handlers.c @@ -3582,8 +3582,8 @@ MHD_request_handle_idle_ (struct MHD_Request *request) time_t timeout; timeout = connection->connection_timeout; if ( (0 != timeout) && - (timeout < (MHD_monotonic_sec_counter () - - connection->last_activity)) ) + (timeout <= (MHD_monotonic_sec_counter () + - connection->last_activity)) ) { MHD_connection_close_ (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index b2d285e3..f4cd774b 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c @@ -4304,8 +4304,8 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) time_t timeout; timeout = connection->connection_timeout; if ( (0 != timeout) && - (timeout < (MHD_monotonic_sec_counter () - - connection->last_activity)) ) + (timeout <= (MHD_monotonic_sec_counter () + - connection->last_activity)) ) { MHD_connection_close_ (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); -- 2.30.2