diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2022-04-27 14:56:18 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2022-04-27 22:11:54 +0300 |
commit | 4ebe2aa5f995d4cbf45c63d277ad1653ffca7725 (patch) | |
tree | e2e461c08ffb487e08ca6c866f240e69b64397c5 /src/microhttpd/daemon.c | |
parent | f3d7ef1f5f1fc9d4e7c24ca3d0ff56dd381e644b (diff) | |
download | libmicrohttpd-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.c | 90 |
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 | */ |
1842 | static uint64_t | 1842 | static uint64_t |
1843 | connection_get_wait (struct MHD_Connection *c) | 1843 | connection_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, |