MINOR: mux-h2: add a per-connection list of blocked streams

Currently the H2 mux doesn't have a list of all the streams blocking on
the H2 side. It only knows about those trying to send or waiting for a
connection window update. It is problematic to enforce timeouts because
we never know if a stream has to live as long as the data layer wants or
has to be timed out becase it's waiting for a stream window update. This
patch adds a new list, "blocked_list", to store streams blocking on
stream flow control, or later, dependencies. Streams blocked on sfctl
are now added there. It doesn't modify the rest of the logic.

(cherry picked from commit 9edf6dbecc9d50d3ab3764b307010a627e39117c)
[wt: dependency for next patch; removed traces]
Signed-off-by: Willy Tarreau <w@1wt.eu>
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 1852482..eeb80b6 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -130,6 +130,7 @@
 	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 */
@@ -168,9 +169,9 @@
 
 /* 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 */
@@ -582,6 +583,7 @@
 	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);
 
@@ -1565,7 +1567,8 @@
 		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);
@@ -1877,7 +1880,8 @@
 		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);
 		}
 	}
@@ -5091,6 +5095,7 @@
 		h2s->flags |= H2_SF_BLK_SFCTL;
 		if (LIST_ADDED(&h2s->list))
 			LIST_DEL_INIT(&h2s->list);
+		LIST_ADDQ(&h2c->blocked_list, &h2s->list);
 		goto end;
 	}
 
@@ -5727,8 +5732,9 @@
 		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);
 	}
 	return total;