Skip to content

Commit feb2be6

Browse files
committed
lws_dll2_t: wsi: switch all handrolled
1 parent 1255a5a commit feb2be6

15 files changed

Lines changed: 491 additions & 464 deletions

File tree

lib/core-net/close.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,10 +1100,8 @@ __lws_close_free_wsi_final(struct lws *wsi)
11001100
wsi->h2.END_STREAM = wsi->h2.END_HEADERS = 0;
11011101
#endif
11021102
#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT) || defined(LWS_ROLE_H3)
1103-
if (wsi->mux.parent_wsi) {
1103+
if (wsi->mux.parent_wsi)
11041104
lws_wsi_mux_sibling_disconnect(wsi);
1105-
wsi->mux.parent_wsi = NULL;
1106-
}
11071105
#endif
11081106

11091107
#if defined(LWS_WITH_TLS)

lib/core-net/private-lib-core-net.h

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,26 @@
3434
*/
3535

3636
struct lws_muxable {
37-
struct lws *parent_wsi;
38-
struct lws *child_list;
39-
struct lws *sibling_list;
37+
struct lws *parent_wsi;
38+
39+
/* mux child/sibling list: parent owns child_list_owner, each child
40+
* composes a sibling_list node. All mutation goes through the
41+
* lws_wsi_mux_* helpers + the lws_dll2 primitives; the link pointers
42+
* must not be hand-edited. */
43+
lws_dll2_owner_t child_list_owner;
44+
lws_dll2_t sibling_list;
4045

4146
/*
4247
* Q-8: was unsigned int. H2 stream IDs are 32-bit, but QUIC stream IDs
4348
* are 62-bit; a 32-bit field silently truncated them, so streams with
4449
* ids >= 2^32 were mis-looked-up and got frames emitted with the wrong
4550
* (truncated) id. uint64_t holds both with room to spare.
4651
*/
47-
uint64_t my_sid;
48-
unsigned int child_count;
52+
uint64_t my_sid;
4953

50-
uint32_t highest_sid;
54+
uint32_t highest_sid;
5155

52-
uint8_t requested_POLLOUT;
56+
uint8_t requested_POLLOUT;
5357
};
5458

5559
#include "private-lib-roles.h"
@@ -660,12 +664,16 @@ __lws_vhost_destroy2(struct lws_vhost *vh);
660664

661665
#define mux_to_wsi(_m) lws_container_of(_m, struct lws, mux)
662666

667+
/* Number of mux children on wsi (kept in child_list_owner.count). */
668+
#define lws_wsi_mux_child_count(_wsi) \
669+
((unsigned int)(_wsi)->mux.child_list_owner.count)
670+
663671
void
664672
lws_wsi_mux_insert(struct lws *wsi, struct lws *parent_wsi, uint64_t sid);
665673
int
666674
lws_wsi_mux_mark_parents_needing_writeable(struct lws *wsi);
667675
struct lws *
668-
lws_wsi_mux_move_child_to_tail(struct lws **wsi2);
676+
lws_wsi_mux_move_child_to_tail(struct lws *parent_wsi);
669677
int
670678
lws_wsi_mux_action_pending_writeable_reqs(struct lws *wsi);
671679

lib/core-net/wsi.c

Lines changed: 57 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,76 +1455,64 @@ void lws_wsi_mux_insert(struct lws *wsi, struct lws *parent_wsi,
14551455
}
14561456
#endif
14571457

1458-
/* new guy's sibling is whoever was the first child before */
1459-
wsi->mux.sibling_list = parent_wsi->mux.child_list;
1460-
1461-
/* first child is now the new guy */
1462-
parent_wsi->mux.child_list = wsi;
1463-
1464-
parent_wsi->mux.child_count++;
1458+
/* new guy becomes the head child of the parent's mux child list */
1459+
lws_dll2_add_head(&wsi->mux.sibling_list, &parent_wsi->mux.child_list_owner);
14651460
}
14661461

14671462
struct lws *lws_wsi_mux_from_id(struct lws *parent_wsi, unsigned int sid) {
1468-
lws_start_foreach_ll(struct lws *, wsi, parent_wsi->mux.child_list) {
1469-
if (wsi->mux.my_sid == sid)
1463+
lws_start_foreach_dll(struct lws_dll2 *, d, parent_wsi->mux.child_list_owner.head) {
1464+
struct lws *wsi = lws_container_of(d, struct lws, mux.sibling_list);
1465+
if ((unsigned int)wsi->mux.my_sid == sid)
14701466
return wsi;
14711467
}
1472-
lws_end_foreach_ll(wsi, mux.sibling_list);
1468+
lws_end_foreach_dll(d);
14731469

14741470
return NULL;
14751471
}
14761472

14771473
void lws_wsi_mux_dump_children(struct lws *wsi) {
14781474
#if defined(_DEBUG)
1475+
struct lws *parent;
1476+
14791477
if (!wsi->mux.parent_wsi || !lwsl_visible(LLL_INFO))
14801478
return;
14811479

1482-
lws_start_foreach_llp(struct lws **, w, wsi->mux.parent_wsi->mux.child_list) {
1480+
parent = wsi->mux.parent_wsi;
1481+
1482+
lws_start_foreach_dll(struct lws_dll2 *, d, parent->mux.child_list_owner.head) {
1483+
struct lws *w = lws_container_of(d, struct lws, mux.sibling_list);
14831484
lwsl_wsi_info(wsi, " \\---- child %s %s\n",
1484-
(*w)->role_ops ? (*w)->role_ops->name : "?", lws_wsi_tag(*w));
1485-
assert(*w != (*w)->mux.sibling_list);
1485+
w->role_ops ? w->role_ops->name : "?", lws_wsi_tag(w));
14861486
}
1487-
lws_end_foreach_llp(w, mux.sibling_list);
1487+
lws_end_foreach_dll(d);
14881488
#endif
14891489
}
14901490

14911491
void lws_wsi_mux_close_children(struct lws *wsi, int reason) {
1492-
struct lws *wsi2;
1493-
struct lws **w;
14941492

1495-
if (!wsi->mux.child_list)
1493+
if (!wsi->mux.child_list_owner.head)
14961494
return;
14971495

1498-
w = &wsi->mux.child_list;
1499-
while (*w) {
1500-
lwsl_wsi_info((*w), " closing child");
1501-
/* disconnect from siblings */
1502-
wsi2 = (*w)->mux.sibling_list;
1503-
assert(wsi2 != *w);
1504-
(*w)->mux.sibling_list = NULL;
1505-
(*w)->socket_is_permanently_unusable = 1;
1506-
__lws_close_free_wsi(*w, (enum lws_close_status)reason,
1496+
lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1497+
wsi->mux.child_list_owner.head) {
1498+
struct lws *w = lws_container_of(d, struct lws, mux.sibling_list);
1499+
1500+
lwsl_wsi_info(w, " closing child");
1501+
w->socket_is_permanently_unusable = 1;
1502+
__lws_close_free_wsi(w, (enum lws_close_status)reason,
15071503
"mux child recurse");
1508-
*w = wsi2;
15091504
}
1505+
lws_end_foreach_dll_safe(d, d1);
15101506
}
15111507

15121508
void lws_wsi_mux_sibling_disconnect(struct lws *wsi) {
1513-
struct lws *wsi2;
15141509

1515-
lws_start_foreach_llp(struct lws **, w, wsi->mux.parent_wsi->mux.child_list) {
1510+
if (!wsi->mux.parent_wsi)
1511+
return;
15161512

1517-
/* disconnect from siblings */
1518-
if (*w == wsi) {
1519-
wsi2 = (*w)->mux.sibling_list;
1520-
(*w)->mux.sibling_list = NULL;
1521-
*w = wsi2;
1522-
lwsl_wsi_debug(wsi, " disentangled from sibling %s", lws_wsi_tag(wsi2));
1523-
break;
1524-
}
1525-
}
1526-
lws_end_foreach_llp(w, mux.sibling_list);
1527-
wsi->mux.parent_wsi->mux.child_count--;
1513+
lws_dll2_remove(&wsi->mux.sibling_list);
1514+
lwsl_wsi_debug(wsi, " disentangled from mux parent %s",
1515+
lws_wsi_tag(wsi->mux.parent_wsi));
15281516

15291517
wsi->mux.parent_wsi = NULL;
15301518
}
@@ -1534,16 +1522,15 @@ void lws_wsi_mux_dump_waiting_children(struct lws *wsi) {
15341522
lwsl_info("%s: %s: children waiting for POLLOUT service:\n", __func__,
15351523
lws_wsi_tag(wsi));
15361524

1537-
wsi = wsi->mux.child_list;
1538-
while (wsi) {
1539-
lwsl_wsi_info(wsi, " %c sid %llu: 0x%x %s %s",
1540-
wsi->mux.requested_POLLOUT ? '*' : ' ',
1541-
(unsigned long long)wsi->mux.my_sid,
1542-
lwsi_state(wsi), wsi->role_ops->name,
1543-
wsi->a.protocol ? wsi->a.protocol->name : "noprotocol");
1544-
1545-
wsi = wsi->mux.sibling_list;
1525+
lws_start_foreach_dll(struct lws_dll2 *, d, wsi->mux.child_list_owner.head) {
1526+
struct lws *w = lws_container_of(d, struct lws, mux.sibling_list);
1527+
lwsl_wsi_info(w, " %c sid %llu: 0x%x %s %s",
1528+
w->mux.requested_POLLOUT ? '*' : ' ',
1529+
(unsigned long long)w->mux.my_sid,
1530+
lwsi_state(w), w->role_ops->name,
1531+
w->a.protocol ? w->a.protocol->name : "noprotocol");
15461532
}
1533+
lws_end_foreach_dll(d);
15471534
#endif
15481535
}
15491536

@@ -1564,43 +1551,33 @@ int lws_wsi_mux_mark_parents_needing_writeable(struct lws *wsi) {
15641551
return 0; // already;
15651552
}
15661553

1567-
struct lws *lws_wsi_mux_move_child_to_tail(struct lws **wsi2) {
1568-
struct lws *w = *wsi2;
1569-
1570-
while (w) {
1571-
if (!w->mux.sibling_list) { /* w is the current last */
1572-
lwsl_wsi_debug(w, "*wsi2 = %s\n", lws_wsi_tag(*wsi2));
1573-
1574-
if (w == *wsi2) /* we are already last */
1575-
break;
1576-
1577-
/* last points to us as new last */
1578-
w->mux.sibling_list = *wsi2;
1554+
/*
1555+
* Move the head mux child of parent_wsi to the tail of its sibling list, and
1556+
* clear its requested_POLLOUT. Returns the moved child (formerly the head),
1557+
* or NULL if there are no children. This implements the fair-share rotation
1558+
* used by the POLLOUT service loops.
1559+
*/
1560+
struct lws *lws_wsi_mux_move_child_to_tail(struct lws *parent_wsi) {
1561+
struct lws_dll2 *head;
1562+
struct lws *w;
15791563

1580-
/* guy pointing to us until now points to
1581-
* our old next */
1582-
*wsi2 = (*wsi2)->mux.sibling_list;
1564+
head = lws_dll2_get_head(&parent_wsi->mux.child_list_owner);
1565+
if (!head)
1566+
return NULL;
15831567

1584-
/* we point to nothing because we are last */
1585-
w->mux.sibling_list->mux.sibling_list = NULL;
1568+
w = lws_container_of(head, struct lws, mux.sibling_list);
15861569

1587-
/* w becomes us */
1588-
w = w->mux.sibling_list;
1589-
break;
1590-
}
1591-
w = w->mux.sibling_list;
1592-
}
1570+
lws_dll2_remove(&w->mux.sibling_list);
1571+
lws_dll2_add_tail(&w->mux.sibling_list,
1572+
&parent_wsi->mux.child_list_owner);
15931573

15941574
/* clear the waiting for POLLOUT on the guy that was chosen */
1595-
1596-
if (w)
1597-
w->mux.requested_POLLOUT = 0;
1575+
w->mux.requested_POLLOUT = 0;
15981576

15991577
return w;
16001578
}
16011579

16021580
int lws_wsi_mux_action_pending_writeable_reqs(struct lws *wsi) {
1603-
struct lws *w = wsi->mux.child_list;
16041581
struct lws *nwsi = lws_get_network_wsi(wsi);
16051582

16061583
if (wsi->mux.requested_POLLOUT) {
@@ -1609,14 +1586,16 @@ int lws_wsi_mux_action_pending_writeable_reqs(struct lws *wsi) {
16091586
return 0;
16101587
}
16111588

1612-
while (w) {
1589+
lws_start_foreach_dll(struct lws_dll2 *, d, wsi->mux.child_list_owner.head) {
1590+
struct lws *w = lws_container_of(d, struct lws, mux.sibling_list);
1591+
16131592
if (w->mux.requested_POLLOUT) {
16141593
if (lws_change_pollfd(nwsi, 0, LWS_POLLOUT))
16151594
return -1;
16161595
return 0;
16171596
}
1618-
w = w->mux.sibling_list;
16191597
}
1598+
lws_end_foreach_dll(d);
16201599

16211600
if (lws_change_pollfd(nwsi, LWS_POLLOUT, 0))
16221601
return -1;

lib/roles/h2/http2.c

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ __lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,
242242
}
243243

244244
/* no more children allowed by parent */
245-
if (parent_wsi->mux.child_count + 1 >
245+
if (lws_wsi_mux_child_count(parent_wsi) + 1 >
246246
parent_wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
247247
lwsl_notice("reached concurrent stream limit\n");
248248
return NULL;
@@ -310,8 +310,7 @@ __lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,
310310

311311
bail1:
312312
/* undo the insert */
313-
parent_wsi->mux.child_list = wsi->mux.sibling_list;
314-
parent_wsi->mux.child_count--;
313+
lws_wsi_mux_sibling_disconnect(wsi);
315314

316315
if (wsi->user_space)
317316
lws_free_set_NULL(wsi->user_space);
@@ -328,7 +327,7 @@ lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi)
328327
struct lws *nwsi = lws_get_network_wsi(parent_wsi);
329328

330329
/* no more children allowed by parent */
331-
if (parent_wsi->mux.child_count + 1 >
330+
if (lws_wsi_mux_child_count(parent_wsi) + 1 >
332331
parent_wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
333332
lwsl_notice("reached concurrent stream limit\n");
334333
return NULL;
@@ -382,8 +381,7 @@ lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi)
382381

383382
bail1:
384383
/* undo the insert */
385-
parent_wsi->mux.child_list = wsi->mux.sibling_list;
386-
parent_wsi->mux.child_count--;
384+
lws_wsi_mux_sibling_disconnect(wsi);
387385

388386
if (wsi->user_space)
389387
lws_free_set_NULL(wsi->user_space);
@@ -582,8 +580,10 @@ lws_h2_settings(struct lws *wsi, struct http2_settings *settings,
582580
* the new value and the old value.
583581
*/
584582

585-
lws_start_foreach_ll(struct lws *, w,
586-
nwsi->mux.child_list) {
583+
lws_start_foreach_dll(struct lws_dll2 *, d,
584+
nwsi->mux.child_list_owner.head) {
585+
struct lws *w = lws_container_of(d, struct lws,
586+
mux.sibling_list);
587587
lwsl_info("%s: adi child tc cr %d +%d -> %d",
588588
__func__, (int)w->txc.tx_cr,
589589
b - (unsigned int)settings->s[a],
@@ -595,7 +595,7 @@ lws_h2_settings(struct lws *wsi, struct http2_settings *settings,
595595
(int32_t)(b - settings->s[a]))
596596

597597
lws_callback_on_writable(w);
598-
} lws_end_foreach_ll(w, mux.sibling_list);
598+
} lws_end_foreach_dll(d);
599599

600600
break;
601601
case H2SET_MAX_FRAME_SIZE:
@@ -1456,7 +1456,7 @@ lws_h2_parse_frame_header(struct lws *wsi)
14561456

14571457
if (!h2n->swsi) {
14581458
/* no more children allowed by parent */
1459-
if (wsi->mux.child_count + 1 >
1459+
if (lws_wsi_mux_child_count(wsi) + 1 >
14601460
wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
14611461
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
14621462
"Another stream not allowed");
@@ -1515,12 +1515,14 @@ lws_h2_parse_frame_header(struct lws *wsi)
15151515
* transitions to the "closed" state when the first frame for
15161516
* stream 7 is sent or received.
15171517
*/
1518-
lws_start_foreach_ll_safe(struct lws *, w, wsi->mux.child_list,
1519-
mux.sibling_list) {
1518+
lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
1519+
wsi->mux.child_list_owner.head) {
1520+
struct lws *w = lws_container_of(d, struct lws,
1521+
mux.sibling_list);
15201522
if (w->mux.my_sid < h2n->sid &&
15211523
w->h2.h2_state == LWS_H2_STATE_IDLE)
15221524
lws_close_free_wsi(w, 0, "h2 sid close");
1523-
} lws_end_foreach_ll_safe(w);
1525+
} lws_end_foreach_dll_safe(d, d1);
15241526

15251527
h2n->cont_exp = !(h2n->flags & LWS_H2_FLAG_END_HEADERS);
15261528
h2n->cont_exp_sid = h2n->sid;
@@ -2152,9 +2154,12 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
21522154
* too)... for us and any children waiting on us... reassess
21532155
* blockage for all children first
21542156
*/
2155-
lws_start_foreach_ll(struct lws *, w, wsi->mux.child_list) {
2157+
lws_start_foreach_dll(struct lws_dll2 *, d,
2158+
wsi->mux.child_list_owner.head) {
2159+
struct lws *w = lws_container_of(d, struct lws,
2160+
mux.sibling_list);
21562161
lws_callback_on_writable(w);
2157-
} lws_end_foreach_ll(w, mux.sibling_list);
2162+
} lws_end_foreach_dll(d);
21582163

21592164
if (eff_wsi->txc.skint &&
21602165
!lws_wsi_txc_check_skint(&eff_wsi->txc,
@@ -2984,10 +2989,13 @@ lws_h2_client_handshake(struct lws *wsi)
29842989
lwsi_set_state(wsi, LRS_ESTABLISHED);
29852990

29862991
if (wsi->mux.my_sid == 1) {
2987-
lws_start_foreach_ll(struct lws *, w1, nwsi->mux.child_list) {
2992+
lws_start_foreach_dll(struct lws_dll2 *, d,
2993+
nwsi->mux.child_list_owner.head) {
2994+
struct lws *w1 = lws_container_of(d, struct lws,
2995+
mux.sibling_list);
29882996
if (w1 != wsi && lwsi_state(w1) == LRS_H2_WAITING_TO_SEND_HEADERS)
29892997
lws_callback_on_writable(w1);
2990-
} lws_end_foreach_ll(w1, mux.sibling_list);
2998+
} lws_end_foreach_dll(d);
29912999
}
29923000

29933001
if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME)

0 commit comments

Comments
 (0)