Skip to content

Commit aa92cea

Browse files
kixelatedclaude
andauthored
refactor: collapse the four AcceptWaiters copies onto kio::Fan (#359)
kio 0.5.4 released `Fan`, so the shared accept list, its waker, and the hold that keeps an inline wake from landing under the accept lock all come from upstream. That deletes 1,264 lines of near-identical `waiters.rs` across the four backends. The `arm`/`disarm` pair becomes a `Hold` guard, which is harder to misuse: there is no count to forget to bring down. It is still dropped explicitly after the accept lock, because where it drops is where a held-back wake is delivered. `Arc<AcceptWaiters>` becomes a plain `Fan` — it is already a shared handle — and the cached wakers come from `Fan::waker()`. iroh and noq carried nothing else in that module, so the file goes. quinn and quiche keep `Parked`, the release-on-`Ready` bridge that kio deliberately does not do, at 56 lines each. Behaviour is unchanged and the accept tests say so: every accepter still gets woken, a departing one still does not strand the others, and an abandoned one still releases its slot. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent b2a4cfd commit aa92cea

14 files changed

Lines changed: 155 additions & 1223 deletions

File tree

rs/web-transport-iroh/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ qlog = ["iroh/qlog"]
2222
bytes = "1"
2323
http = "1"
2424
iroh = { version = "1", default-features = false, features = ["fast-apple-datapath"] }
25-
kio = "0.5.3"
25+
kio = "0.5.4"
2626
n0-error = "1"
2727
n0-future = "0.3.1"
2828
tokio = { version = "1", default-features = false, features = [

rs/web-transport-iroh/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ mod session;
3232
mod settings;
3333
#[cfg(test)]
3434
mod tests;
35-
mod waiters;
3635

3736
pub use client::*;
3837
pub use connect::*;

rs/web-transport-iroh/src/session.rs

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::{
1010

1111
use bytes::{Bytes, BytesMut};
1212
use iroh::endpoint::{self, Connection, PathStats};
13-
use kio::Waiter;
13+
use kio::{Fan, Waiter};
1414
use n0_future::{
1515
FuturesUnordered,
1616
stream::{Stream, StreamExt},
@@ -19,7 +19,6 @@ use web_transport_proto::{ConnectRequest, ConnectResponse, Frame, StreamUni, Var
1919

2020
use crate::{
2121
ClientError, Connected, RecvStream, SendStream, SessionError, Settings, WebTransportError,
22-
waiters::AcceptWaiters,
2322
};
2423

2524
/// An established WebTransport session, acting like a full QUIC connection. See [`iroh::endpoint::Connection`].
@@ -378,21 +377,24 @@ fn poll_accept_uni_shared(
378377
accept: &Mutex<H3SessionAccept>,
379378
waiter: &Waiter,
380379
) -> Poll<Result<RecvStream, SessionError>> {
381-
let (result, waiters) = {
380+
let (result, waiters, hold) = {
382381
let mut accept = accept.lock().unwrap();
383382
let waiters = accept.uni_waiters.clone();
384383

385-
// The poll below drives the shared accept futures with this list's waker, and
386-
// one of them may wake it inline. Hold those back until the lock is gone.
387-
waiters.arm();
384+
// The poll below drives the shared accept futures with this list's waker, and one
385+
// of them may wake it inline. `Fan` holds those back while this guard is alive.
386+
let hold = waiters.hold();
388387
let result = accept.poll_accept_uni(waiter);
389388

390-
(result, waiters)
389+
(result, waiters, hold)
391390
};
392391

393-
// `disarm` runs first either way: the count has to come down even on a `Ready`.
394-
if waiters.disarm() || result.is_ready() {
395-
waiters.wake_all();
392+
// Dropped after the accept lock, never before: that is where a held-back wake is
393+
// delivered, and delivering it under the lock is the hazard the hold exists for.
394+
drop(hold);
395+
396+
if result.is_ready() {
397+
waiters.wake();
396398
}
397399

398400
result
@@ -402,21 +404,24 @@ fn poll_accept_bi_shared(
402404
accept: &Mutex<H3SessionAccept>,
403405
waiter: &Waiter,
404406
) -> Poll<Result<(SendStream, RecvStream), SessionError>> {
405-
let (result, waiters) = {
407+
let (result, waiters, hold) = {
406408
let mut accept = accept.lock().unwrap();
407409
let waiters = accept.bi_waiters.clone();
408410

409-
// The poll below drives the shared accept futures with this list's waker, and
410-
// one of them may wake it inline. Hold those back until the lock is gone.
411-
waiters.arm();
411+
// The poll below drives the shared accept futures with this list's waker, and one
412+
// of them may wake it inline. `Fan` holds those back while this guard is alive.
413+
let hold = waiters.hold();
412414
let result = accept.poll_accept_bi(waiter);
413415

414-
(result, waiters)
416+
(result, waiters, hold)
415417
};
416418

417-
// `disarm` runs first either way: the count has to come down even on a `Ready`.
418-
if waiters.disarm() || result.is_ready() {
419-
waiters.wake_all();
419+
// Dropped after the accept lock, never before: that is where a held-back wake is
420+
// delivered, and delivering it under the lock is the hazard the hold exists for.
421+
drop(hold);
422+
423+
if result.is_ready() {
424+
waiters.wake();
420425
}
421426

422427
result
@@ -442,8 +447,8 @@ struct H3SessionAccept {
442447
// Every clone of the session polls this one struct, so an arrival has to be fanned
443448
// out: each caller registers here and all of them are woken when a stream lands —
444449
// by the caller that saw it, once it has released the lock on this struct.
445-
bi_waiters: Arc<AcceptWaiters>,
446-
uni_waiters: Arc<AcceptWaiters>,
450+
bi_waiters: Fan,
451+
uni_waiters: Fan,
447452

448453
// `Waker::from(waiters.clone())`, cached so the inner accept futures are polled with
449454
// the same waker every time. That waker outlives every caller, so an accepter that
@@ -464,10 +469,10 @@ impl H3SessionAccept {
464469
Some((conn.accept_bi().await, conn))
465470
}));
466471

467-
let bi_waiters = Arc::new(AcceptWaiters::default());
468-
let uni_waiters = Arc::new(AcceptWaiters::default());
469-
let bi_waker = Waker::from(bi_waiters.clone());
470-
let uni_waker = Waker::from(uni_waiters.clone());
472+
let bi_waiters = Fan::new();
473+
let uni_waiters = Fan::new();
474+
let bi_waker = bi_waiters.waker();
475+
let uni_waker = uni_waiters.waker();
471476

472477
Self {
473478
session_id,

0 commit comments

Comments
 (0)