diff --git a/include/proto/connection.h b/include/proto/connection.h index e4621ccbd..35b9dfe49 100644 --- a/include/proto/connection.h +++ b/include/proto/connection.h @@ -601,6 +601,7 @@ static inline void cs_init(struct conn_stream *cs, struct connection *conn) LIST_INIT(&cs->wait_list.list); LIST_INIT(&cs->send_wait_list); cs->conn = conn; + cs->wait_list.wait_reason = 0; } /* Initializes all required fields for a new connection. Note that it does the diff --git a/include/types/connection.h b/include/types/connection.h index abe85a477..9a1ba9667 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -44,9 +44,15 @@ struct buffer; struct server; struct pipe; +enum sub_event_type { + SUB_CAN_SEND = 0x00000001, /* Schedule the tasklet when we can send more */ + SUB_CAN_RECV = 0x00000002, /* Schedule the tasklet when we can recv more */ +}; + struct wait_list { struct tasklet *task; struct list list; + int wait_reason; }; /* A connection handle is how we differenciate two connections on the lower @@ -90,9 +96,6 @@ enum cs_shw_mode { CS_SHW_SILENT = 1, /* imminent close, don't notify peer */ }; -enum sub_event_type { - SUB_CAN_SEND = 0x00000001, /* Schedule the tasklet when we can send more */ -}; /* For each direction, we have a CO_FL_{SOCK,DATA}__ENA flag, which * indicates if read or write is desired in that direction for the respective * layers. The current status corresponding to the current layer being used is diff --git a/src/connection.c b/src/connection.c index df3df8426..ee80e616f 100644 --- a/src/connection.c +++ b/src/connection.c @@ -134,6 +134,7 @@ void conn_fd_handler(int fd) struct wait_list *, list); LIST_DEL(&sw->list); LIST_INIT(&sw->list); + sw->wait_reason &= ~SUB_CAN_SEND; tasklet_wakeup(sw->task); } } @@ -338,8 +339,10 @@ int conn_subscribe(struct connection *conn, int event_type, void *param) switch (event_type) { case SUB_CAN_SEND: sw = param; - if (LIST_ISEMPTY(&sw->list)) + if (!(sw->wait_reason & SUB_CAN_SEND)) { + sw->wait_reason |= SUB_CAN_SEND; LIST_ADDQ(&conn->send_wait_list, &sw->list); + } return 0; default: break; diff --git a/src/mux_h2.c b/src/mux_h2.c index 0ad4bac20..538d21f07 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -369,6 +369,7 @@ static int h2c_frt_init(struct connection *conn) goto fail; h2c->wait_list.task->process = h2_send; h2c->wait_list.task->context = conn; + h2c->wait_list.wait_reason = 0; h2c->ddht = hpack_dht_alloc(h2_settings_header_table_size); if (!h2c->ddht) @@ -2289,6 +2290,7 @@ static struct task *h2_send(struct task *t, void *ctx, unsigned short state) struct wait_list *, list); LIST_DEL(&sw->list); LIST_INIT(&sw->list); + sw->wait_reason &= ~SUB_CAN_SEND; tasklet_wakeup(sw->task); } @@ -3409,8 +3411,11 @@ static int h2_subscribe(struct conn_stream *cs, int event_type, void *param) switch (event_type) { case SUB_CAN_SEND: sw = param; - if (LIST_ISEMPTY(&h2s->list) && LIST_ISEMPTY(&sw->list)) + if (LIST_ISEMPTY(&h2s->list) && + !(sw->wait_reason & SUB_CAN_SEND)) { LIST_ADDQ(&h2s->h2c->send_wait_list, &sw->list); + sw->wait_reason |= SUB_CAN_SEND; + } return 0; default: break; diff --git a/src/stream_interface.c b/src/stream_interface.c index f2d6b6f5b..92b8e85c3 100644 --- a/src/stream_interface.c +++ b/src/stream_interface.c @@ -652,7 +652,7 @@ static struct task * si_cs_send(struct task *t, void *ctx, unsigned short state) int did_send = 0; /* We're already waiting to be able to send, give up */ - if (!LIST_ISEMPTY(&cs->wait_list.list)) + if (cs->wait_list.wait_reason & SUB_CAN_SEND) return NULL; if (conn->flags & CO_FL_ERROR || cs->flags & CS_FL_ERROR) @@ -661,7 +661,7 @@ static struct task * si_cs_send(struct task *t, void *ctx, unsigned short state) if (conn->flags & CO_FL_HANDSHAKE) { /* a handshake was requested */ /* Schedule ourself to be woken up once the handshake is done */ - LIST_ADDQ(&conn->send_wait_list, &cs->wait_list.list); + conn->xprt->subscribe(conn, SUB_CAN_SEND, wl_set_waitcb(&cs->wait_list, si_cs_send, ctx)); return NULL; } @@ -751,6 +751,7 @@ wake_others: struct wait_list *, list); LIST_DEL(&sw->list); LIST_INIT(&sw->list); + sw->wait_reason &= ~SUB_CAN_SEND; tasklet_wakeup(sw->task); } }