struct eb_root streams_by_id; /* all active streams by their ID */
struct list send_list; /* list of blocked streams requesting to send */
struct list fctl_list; /* list of streams blocked by connection's fctl */
+ struct list blocked_list; /* list of streams blocked for other reasons (e.g. sfctl, dep) */
struct list sending_list; /* list of h2s scheduled to send data */
struct buffer_wait buf_wait; /* wait list for buffer allocations */
struct wait_event wait_event; /* To be used if we're waiting for I/Os */
/* stream flags indicating the reason the stream is blocked */
#define H2_SF_BLK_MBUSY 0x00000010 // blocked waiting for mux access (transient)
-#define H2_SF_BLK_MROOM 0x00000020 // blocked waiting for room in the mux
-#define H2_SF_BLK_MFCTL 0x00000040 // blocked due to mux fctl
-#define H2_SF_BLK_SFCTL 0x00000080 // blocked due to stream fctl
+#define H2_SF_BLK_MROOM 0x00000020 // blocked waiting for room in the mux (must be in send list)
+#define H2_SF_BLK_MFCTL 0x00000040 // blocked due to mux fctl (must be in fctl list)
+#define H2_SF_BLK_SFCTL 0x00000080 // blocked due to stream fctl (must be in blocked list)
#define H2_SF_BLK_ANY 0x000000F0 // any of the reasons above
/* stream flags indicating how data is supposed to be sent */
h2c->streams_by_id = EB_ROOT;
LIST_INIT(&h2c->send_list);
LIST_INIT(&h2c->fctl_list);
+ LIST_INIT(&h2c->blocked_list);
LIST_INIT(&h2c->sending_list);
LIST_INIT(&h2c->buf_wait.list);
h2s = container_of(node, struct h2s, by_id);
if (h2s->flags & H2_SF_BLK_SFCTL && h2s_mws(h2s) > 0) {
h2s->flags &= ~H2_SF_BLK_SFCTL;
- if (h2s->send_wait && !LIST_ADDED(&h2s->list))
+ LIST_DEL_INIT(&h2s->list);
+ if (h2s->send_wait)
LIST_ADDQ(&h2c->send_list, &h2s->list);
}
node = eb32_next(node);
h2s->sws += inc;
if (h2s_mws(h2s) > 0 && (h2s->flags & H2_SF_BLK_SFCTL)) {
h2s->flags &= ~H2_SF_BLK_SFCTL;
- if (h2s->send_wait && !LIST_ADDED(&h2s->list))
+ LIST_DEL_INIT(&h2s->list);
+ if (h2s->send_wait)
LIST_ADDQ(&h2c->send_list, &h2s->list);
}
}
h2s->flags |= H2_SF_BLK_SFCTL;
if (LIST_ADDED(&h2s->list))
LIST_DEL_INIT(&h2s->list);
+ LIST_ADDQ(&h2c->blocked_list, &h2s->list);
TRACE_STATE("stream window <=0, flow-controlled", H2_EV_TX_FRAME|H2_EV_TX_DATA|H2_EV_H2S_FCTL, h2c->conn, h2s);
goto end;
}
else
cs->flags |= CS_FL_ERR_PENDING;
}
- if (total > 0) {
- /* Ok we managed to send something, leave the send_list */
+
+ if (total > 0 && !(h2s->flags & H2_SF_BLK_SFCTL)) {
+ /* Ok we managed to send something, leave the send_list if we were still there */
LIST_DEL_INIT(&h2s->list);
}
+
TRACE_LEAVE(H2_EV_H2S_SEND|H2_EV_STRM_SEND, h2s->h2c->conn, h2s);
return total;
}