mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
timeout move to doubly linked list
In the case we have a lot of connections, checking them all for timeout state once a second becomes burdensome. At the moment if you have 100K connections, once a second they all get checked for timeout in a loop. This patch adds a doubly-linked list based in the context to each wsi, and only wsi with pending timeouts appear on it. At checking time, we traverse the list, which costs nothing if empty because nobody has a pending timeout. Similarly adding and removing from the list costs almost nothing since no iteration is required no matter how big the list. The extra 8 or 16 bytes in the wsi are offset a little bit by demoting .pps from int to char (save 3 bytes). And trim max act exts to 2, since we only provide one, saving 8 /16 bytes by itself if exts enabled. Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
parent
15c92b1bf6
commit
d738f84ed1
3 changed files with 37 additions and 13 deletions
|
@ -68,6 +68,19 @@ lws_free_wsi(struct lws *wsi)
|
|||
lws_free(wsi);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
lws_remove_from_timeout_list(struct lws *wsi)
|
||||
{
|
||||
if (!wsi->timeout_list_prev)
|
||||
return;
|
||||
|
||||
*wsi->timeout_list_prev = wsi->timeout_list;
|
||||
wsi->timeout_list_prev = NULL;
|
||||
wsi->timeout_list = NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
|
||||
{
|
||||
|
@ -234,6 +247,7 @@ just_kill_connection:
|
|||
* delete socket from the internal poll list if still present
|
||||
*/
|
||||
lws_ssl_remove_wsi_from_buffered_list(wsi);
|
||||
lws_remove_from_timeout_list(wsi);
|
||||
|
||||
/* checking return redundant since we anyway close */
|
||||
remove_wsi_socket_from_fds(wsi);
|
||||
|
@ -563,8 +577,19 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
|
|||
|
||||
time(&now);
|
||||
|
||||
if (!wsi->pending_timeout) {
|
||||
wsi->timeout_list = wsi->context->timeout_list;
|
||||
if (wsi->timeout_list)
|
||||
wsi->timeout_list->timeout_list_prev = &wsi->timeout_list;
|
||||
wsi->timeout_list_prev = &wsi->context->timeout_list;
|
||||
*wsi->timeout_list_prev = wsi;
|
||||
}
|
||||
|
||||
wsi->pending_timeout_limit = now + secs;
|
||||
wsi->pending_timeout = reason;
|
||||
|
||||
if (!reason)
|
||||
lws_remove_from_timeout_list(wsi);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1144,7 +1169,7 @@ lws_parse_uri(char *p, const char **prot, const char **ads, int *port, const cha
|
|||
*port = 80;
|
||||
else if (!strcmp(*prot, "https") || !strcmp(*prot, "wss"))
|
||||
*port = 443;
|
||||
|
||||
|
||||
while (*p && *p != ':' && *p != '/')
|
||||
p++;
|
||||
if (*p == ':') {
|
||||
|
|
|
@ -290,7 +290,7 @@ extern "C" {
|
|||
#define LWS_MAX_PROTOCOLS 5
|
||||
#endif
|
||||
#ifndef LWS_MAX_EXTENSIONS_ACTIVE
|
||||
#define LWS_MAX_EXTENSIONS_ACTIVE 3
|
||||
#define LWS_MAX_EXTENSIONS_ACTIVE 2
|
||||
#endif
|
||||
#ifndef LWS_MAX_EXT_OFFERS
|
||||
#define LWS_MAX_EXT_OFFERS 8
|
||||
|
@ -522,6 +522,8 @@ struct lws_context {
|
|||
const char *iface;
|
||||
const struct lws_token_limits *token_limits;
|
||||
void *user_space;
|
||||
struct lws *timeout_list;
|
||||
|
||||
#ifndef LWS_NO_SERVER
|
||||
struct lws *wsi_listening;
|
||||
#endif
|
||||
|
@ -907,6 +909,8 @@ struct lws {
|
|||
|
||||
struct lws_context *context;
|
||||
const struct lws_protocols *protocol;
|
||||
struct lws *timeout_list;
|
||||
struct lws **timeout_list_prev;
|
||||
void *user_space;
|
||||
/* rxflow handling */
|
||||
unsigned char *rxflow_buffer;
|
||||
|
@ -929,7 +933,6 @@ struct lws {
|
|||
lws_sockfd_type sock;
|
||||
|
||||
/* ints */
|
||||
enum lws_pending_protocol_send pps;
|
||||
int position_in_fds_table;
|
||||
int rxflow_len;
|
||||
int rxflow_pos;
|
||||
|
@ -962,6 +965,7 @@ struct lws {
|
|||
char lws_rx_parse_state; /* enum lws_rx_parse_state */
|
||||
char rx_frame_type; /* enum lws_write_protocol */
|
||||
char pending_timeout; /* enum pending_timeout */
|
||||
char pps; /* enum lws_pending_protocol_send */
|
||||
};
|
||||
|
||||
LWS_EXTERN int log_level;
|
||||
|
|
|
@ -298,8 +298,7 @@ lws_service_timeout_check(struct lws *wsi, unsigned int sec)
|
|||
* if extensions want in on it (eg, we are a mux parent)
|
||||
* give them a chance to service child timeouts
|
||||
*/
|
||||
if (lws_ext_cb_active(wsi, LWS_EXT_CB_1HZ,
|
||||
NULL, sec) < 0)
|
||||
if (lws_ext_cb_active(wsi, LWS_EXT_CB_1HZ, NULL, sec) < 0)
|
||||
return 0;
|
||||
|
||||
if (!wsi->pending_timeout)
|
||||
|
@ -380,7 +379,6 @@ lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd)
|
|||
struct lws_tokens eff_buf;
|
||||
unsigned int pending = 0;
|
||||
char draining_flow = 0;
|
||||
lws_sockfd_type mfd;
|
||||
int timed_out = 0;
|
||||
struct lws *wsi;
|
||||
time_t now;
|
||||
|
@ -410,18 +408,15 @@ lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd)
|
|||
if (pollfd)
|
||||
our_fd = pollfd->fd;
|
||||
|
||||
for (n = 0; n < context->fds_count; n++) {
|
||||
mfd = context->fds[n].fd;
|
||||
wsi = wsi_from_fd(context, mfd);
|
||||
if (!wsi)
|
||||
continue;
|
||||
|
||||
wsi = context->timeout_list;
|
||||
while (wsi) {
|
||||
if (lws_service_timeout_check(wsi, (unsigned int)now))
|
||||
/* he did time out... */
|
||||
if (mfd == our_fd)
|
||||
if (wsi->sock == our_fd)
|
||||
/* it was the guy we came to service! */
|
||||
timed_out = 1;
|
||||
/* he's gone, no need to mark as handled */
|
||||
wsi = wsi->timeout_list;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue