aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/daemon.c
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-04-27 14:56:18 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-04-27 22:11:54 +0300
commit4ebe2aa5f995d4cbf45c63d277ad1653ffca7725 (patch)
treee2e461c08ffb487e08ca6c866f240e69b64397c5 /src/microhttpd/daemon.c
parentf3d7ef1f5f1fc9d4e7c24ca3d0ff56dd381e644b (diff)
downloadlibmicrohttpd-4ebe2aa5f995d4cbf45c63d277ad1653ffca7725.tar.gz
libmicrohttpd-4ebe2aa5f995d4cbf45c63d277ad1653ffca7725.zip
thread-per-connection: improved timeout handling for 'poll()' mode, fixed short busy-waiting
* Avoid unneeded wake-ups * More precise timeout with milliseconds accuracy * Fixed potential short (less than one second) busy waiting when connection is about to expire.
Diffstat (limited to 'src/microhttpd/daemon.c')
-rw-r--r--src/microhttpd/daemon.c90
1 files changed, 52 insertions, 38 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index e9207490..1ec58e06 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -1836,8 +1836,8 @@ thread_main_connection_upgrade (struct MHD_Connection *con)
1836 * Get maximum wait period for the connection (the amount of time left before 1836 * Get maximum wait period for the connection (the amount of time left before
1837 * connection time out) 1837 * connection time out)
1838 * @param c the connection to check 1838 * @param c the connection to check
1839 * @return the maximum wait period before the connection must be processed 1839 * @return the maximum number of millisecond before the connection must be
1840 * again. 1840 * processed again.
1841 */ 1841 */
1842static uint64_t 1842static uint64_t
1843connection_get_wait (struct MHD_Connection *c) 1843connection_get_wait (struct MHD_Connection *c)
@@ -1897,8 +1897,6 @@ thread_main_handle_connection (void *data)
1897 fd_set ws; 1897 fd_set ws;
1898 fd_set es; 1898 fd_set es;
1899 MHD_socket maxsock; 1899 MHD_socket maxsock;
1900 struct timeval tv;
1901 struct timeval *tvp;
1902#if WINDOWS 1900#if WINDOWS
1903#ifdef HAVE_POLL 1901#ifdef HAVE_POLL
1904 int extra_slot; 1902 int extra_slot;
@@ -1922,6 +1920,7 @@ thread_main_handle_connection (void *data)
1922 while ( (! daemon->shutdown) && 1920 while ( (! daemon->shutdown) &&
1923 (MHD_CONNECTION_CLOSED != con->state) ) 1921 (MHD_CONNECTION_CLOSED != con->state) )
1924 { 1922 {
1923 bool use_zero_timeout;
1925#ifdef UPGRADE_SUPPORT 1924#ifdef UPGRADE_SUPPORT
1926 struct MHD_UpgradeResponseHandle *const urh = con->urh; 1925 struct MHD_UpgradeResponseHandle *const urh = con->urh;
1927#else /* ! UPGRADE_SUPPORT */ 1926#else /* ! UPGRADE_SUPPORT */
@@ -1999,40 +1998,40 @@ thread_main_handle_connection (void *data)
1999 was_suspended = false; 1998 was_suspended = false;
2000 } 1999 }
2001 2000
2002 tvp = NULL; 2001 use_zero_timeout = ( (MHD_EVENT_LOOP_INFO_BLOCK == con->event_loop_info)
2003
2004 if ( (MHD_EVENT_LOOP_INFO_BLOCK == con->event_loop_info)
2005#ifdef HTTPS_SUPPORT 2002#ifdef HTTPS_SUPPORT
2006 || ( (con->tls_read_ready) && 2003 || ( (con->tls_read_ready) && \
2007 (MHD_EVENT_LOOP_INFO_READ == con->event_loop_info) ) 2004 (MHD_EVENT_LOOP_INFO_READ ==
2005 con->event_loop_info) )
2008#endif /* HTTPS_SUPPORT */ 2006#endif /* HTTPS_SUPPORT */
2009 ) 2007 );
2010 {
2011 /* do not block: more data may be inside of TLS buffers waiting or
2012 * application must provide response data */
2013 tv.tv_sec = 0;
2014 tv.tv_usec = 0;
2015 tvp = &tv;
2016 }
2017 if ( (NULL == tvp) &&
2018 (con->connection_timeout_ms > 0) )
2019 {
2020 const uint64_t mseconds_left = connection_get_wait (con);
2021#if (SIZEOF_UINT64_T - 2) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC
2022 if (mseconds_left / 1000 > TIMEVAL_TV_SEC_MAX)
2023 tv.tv_sec = TIMEVAL_TV_SEC_MAX;
2024 else
2025#endif /* (SIZEOF_UINT64_T - 2) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC */
2026 tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) mseconds_left / 1000;
2027
2028 tv.tv_usec = (mseconds_left % 1000) * 1000;
2029
2030 tvp = &tv;
2031 }
2032 if (! use_poll) 2008 if (! use_poll)
2033 { 2009 {
2034 /* use select */ 2010 /* use select */
2035 bool err_state = false; 2011 bool err_state = false;
2012 struct timeval tv;
2013 struct timeval *tvp;
2014 if (use_zero_timeout)
2015 {
2016 tv.tv_sec = 0;
2017 tv.tv_usec = 0;
2018 tvp = &tv;
2019 }
2020 else if (con->connection_timeout_ms > 0)
2021 {
2022 const uint64_t mseconds_left = connection_get_wait (con);
2023#if (SIZEOF_UINT64_T - 2) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC
2024 if (mseconds_left / 1000 > TIMEVAL_TV_SEC_MAX)
2025 tv.tv_sec = TIMEVAL_TV_SEC_MAX;
2026 else
2027#endif /* (SIZEOF_UINT64_T - 2) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC */
2028 tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) mseconds_left / 1000;
2029
2030 tv.tv_usec = ((uint16_t) (mseconds_left % 1000)) * 1000;
2031 tvp = &tv;
2032 }
2033 else
2034 tvp = NULL;
2036 2035
2037 FD_ZERO (&rs); 2036 FD_ZERO (&rs);
2038 FD_ZERO (&ws); 2037 FD_ZERO (&ws);
@@ -2124,7 +2123,22 @@ thread_main_handle_connection (void *data)
2124#ifdef HAVE_POLL 2123#ifdef HAVE_POLL
2125 else 2124 else
2126 { 2125 {
2126 int timeout_val;
2127 /* use poll */ 2127 /* use poll */
2128 if (use_zero_timeout)
2129 timeout_val = 0;
2130 else if (con->connection_timeout_ms > 0)
2131 {
2132 const uint64_t mseconds_left = connection_get_wait (con);
2133#if SIZEOF_UINT64_T >= SIZEOF_INT
2134 if (mseconds_left >= INT_MAX)
2135 timeout_val = INT_MAX;
2136 else
2137#endif /* SIZEOF_UINT64_T >= SIZEOF_INT */
2138 timeout_val = (int) mseconds_left;
2139 }
2140 else
2141 timeout_val = -1;
2128 memset (&p, 2142 memset (&p,
2129 0, 2143 0,
2130 sizeof (p)); 2144 sizeof (p));
@@ -2160,7 +2174,7 @@ thread_main_handle_connection (void *data)
2160#else 2174#else
2161 1, 2175 1,
2162#endif 2176#endif
2163 (NULL == tvp) ? -1 : (tv.tv_sec * 1000)) < 0) 2177 timeout_val) < 0)
2164 { 2178 {
2165 if (MHD_SCKT_LAST_ERR_IS_ (MHD_SCKT_EINTR_)) 2179 if (MHD_SCKT_LAST_ERR_IS_ (MHD_SCKT_EINTR_))
2166 continue; 2180 continue;
@@ -4617,7 +4631,7 @@ MHD_poll_listen_socket (struct MHD_Daemon *daemon,
4617 p[poll_count].fd = ls; 4631 p[poll_count].fd = ls;
4618 p[poll_count].events = POLLIN; 4632 p[poll_count].events = POLLIN;
4619 p[poll_count].revents = 0; 4633 p[poll_count].revents = 0;
4620 poll_listen = poll_count; 4634 poll_listen = (int) poll_count;
4621 poll_count++; 4635 poll_count++;
4622 } 4636 }
4623 if (MHD_ITC_IS_VALID_ (daemon->itc)) 4637 if (MHD_ITC_IS_VALID_ (daemon->itc))
@@ -4625,7 +4639,7 @@ MHD_poll_listen_socket (struct MHD_Daemon *daemon,
4625 p[poll_count].fd = MHD_itc_r_fd_ (daemon->itc); 4639 p[poll_count].fd = MHD_itc_r_fd_ (daemon->itc);
4626 p[poll_count].events = POLLIN; 4640 p[poll_count].events = POLLIN;
4627 p[poll_count].revents = 0; 4641 p[poll_count].revents = 0;
4628 poll_itc_idx = poll_count; 4642 poll_itc_idx = (int) poll_count;
4629 poll_count++; 4643 poll_count++;
4630 } 4644 }
4631 4645
@@ -4653,7 +4667,7 @@ MHD_poll_listen_socket (struct MHD_Daemon *daemon,
4653#endif 4667#endif
4654 return MHD_NO; 4668 return MHD_NO;
4655 } 4669 }
4656 if ( (-1 != poll_itc_idx) && 4670 if ( (0 <= poll_itc_idx) &&
4657 (0 != (p[poll_itc_idx].revents & POLLIN)) ) 4671 (0 != (p[poll_itc_idx].revents & POLLIN)) )
4658 MHD_itc_clear_ (daemon->itc); 4672 MHD_itc_clear_ (daemon->itc);
4659 4673
@@ -4665,7 +4679,7 @@ MHD_poll_listen_socket (struct MHD_Daemon *daemon,
4665 if (daemon->have_new) 4679 if (daemon->have_new)
4666 new_connections_list_process_ (daemon); 4680 new_connections_list_process_ (daemon);
4667 4681
4668 if ( (-1 != poll_listen) && 4682 if ( (0 <= poll_listen) &&
4669 (0 != (p[poll_listen].revents & POLLIN)) ) 4683 (0 != (p[poll_listen].revents & POLLIN)) )
4670 (void) MHD_accept_connection (daemon); 4684 (void) MHD_accept_connection (daemon);
4671 return MHD_YES; 4685 return MHD_YES;
@@ -6932,7 +6946,7 @@ MHD_start_daemon_va (unsigned int flags,
6932 } 6946 }
6933#endif 6947#endif
6934 if (listen (listen_fd, 6948 if (listen (listen_fd,
6935 daemon->listen_backlog_size) < 0) 6949 (int) daemon->listen_backlog_size) < 0)
6936 { 6950 {
6937#ifdef HAVE_MESSAGES 6951#ifdef HAVE_MESSAGES
6938 MHD_DLOG (daemon, 6952 MHD_DLOG (daemon,