Skip to content

feat(daemon): tokio async listener behind --features async-daemon (#1935)#4278

Merged
oferchen merged 1 commit into
masterfrom
feat/daemon-async-tokio-listener-1935
May 17, 2026
Merged

feat(daemon): tokio async listener behind --features async-daemon (#1935)#4278
oferchen merged 1 commit into
masterfrom
feat/daemon-async-tokio-listener-1935

Conversation

@oferchen
Copy link
Copy Markdown
Owner

Summary

  • Adds the implementation skeleton for the hybrid daemon listener accepted in docs/design/daemon-async-runtime-choice.md: tokio multi-thread runtime drives tokio::net::TcpListener::accept, and each accepted connection is handed to the synchronous worker via tokio::task::spawn_blocking.
  • New async-daemon cargo feature, off by default. Default builds stay tokio-free and continue to dispatch through the existing serve_connections thread-per-connection loop.
  • Skeleton is wired through daemon::run_async_daemon, which reuses the existing config parsing and signal-flag plumbing. The per-connection worker is a documented stub; production wiring to the sync session handler is the follow-up tracked under Normalize quoted fallback keywords #1935 once the trigger conditions in the runtime-choice ADR are met (sustained >1k concurrent connections, blocking-pool starvation measurements, two release cycles of green async-daemon CI).

Files

  • crates/daemon/Cargo.toml - declares the async-daemon feature and extends the optional tokio feature list with rt-multi-thread and macros.
  • crates/daemon/src/async_listener.rs - new module exposing run_hybrid_listener(addr, worker_threads, shutdown, SyncWorker) plus accept loop, with unit tests for bind/accept/dispatch and prompt shutdown.
  • crates/daemon/src/daemon.rs - adds run_async_daemon, gated by async-daemon, which feeds the parsed runtime options into the new listener and hooks into the existing signal flags.
  • crates/daemon/src/lib.rs - re-exports async_listener and run_async_daemon behind the feature flag.

Test plan

  • CI fmt+clippy on default features
  • CI fmt+clippy with --features async-daemon
  • CI nextest with --features async-daemon exercises the two new unit tests in async_listener::tests
  • Linux musl, macOS, and Windows matrices all build the new feature

References

  • Issue: Normalize quoted fallback keywords #1935
  • Runtime choice ADR: docs/design/daemon-async-runtime-choice.md
  • Implementation plan: docs/design/daemon-tokio-async-listener-impl.md
  • Hybrid model rationale: docs/design/daemon-async-accept-sync-workers.md

)

Adds the implementation skeleton for the hybrid daemon listener accepted
in the runtime-choice ADR: a tokio multi-thread runtime drives
TcpListener::accept while each connection is handed to the existing
synchronous worker via spawn_blocking. Default builds remain tokio-free.

- New `async-daemon` cargo feature gates the entire path.
- `crates/daemon/src/async_listener.rs` exposes `run_hybrid_listener`,
  taking an `Arc<dyn Fn>` sync worker and a shutdown flag. Unit tests
  bind on an ephemeral port and confirm accept-and-dispatch plus prompt
  shutdown work end-to-end.
- `daemon::run_async_daemon` wires the listener to the existing daemon
  config and signal-flag plumbing. The per-connection worker is a
  documented stub; production wiring to the sync session handler ships in
  the follow-up tracked under #1935 once the trigger conditions from
  `docs/design/daemon-async-runtime-choice.md` are met.
- Tokio features extended with `rt-multi-thread` and `macros` so the new
  builder path compiles alongside the existing `async` feature.
@oferchen oferchen merged commit d9f2ae2 into master May 17, 2026
12 of 14 checks passed
oferchen added a commit that referenced this pull request May 17, 2026
… (#4285)

Audits whether prerequisites for #1876 have landed and proposes
splitting the work into reviewable subtasks (#1876-a through e).

- #1874 (shared ring + POLL_ADD) shipped via PR #3553.
- #1937 (session ring pool) shipped via PR #4275.
- #1935 (hybrid tokio listener) shipped via PR #4278.
- No io_uring task carries id #1875; the original dependency note
  most plausibly meant the session-pool and listener work above.

Missing surface enumerated: pooled-ring constructors on the socket
adapters, daemon plumbing for SessionRingPool, sync and async worker
swaps, IORING_OP_LINK_TIMEOUT integration, and async-cancel
discipline. Trigger conditions (kernel >= 5.6, io_uring feature,
opt-in flag) and a five-step implementation plan included.
oferchen added a commit that referenced this pull request May 17, 2026
Scaffold the `IORING_OP_ASYNC_CANCEL` primitive now that the async daemon
listener (#4278), session ring pool (#4275), and per-thread rings (#4288)
have landed code paths that keep SQEs in-flight across abort decision
points. Until now, every io_uring helper followed `submit + wait + drain`
and never needed cancellation; the deferred design at
`docs/design/iouring-async-cancel.md` documented the trigger condition
this commit fulfils.

- New module `crates/fast_io/src/io_uring/cancel.rs` (Linux + `io_uring`
  feature gated):
  - `cancel_by_user_data(&mut IoUring, u64) -> io::Result<CancelOutcome>`
    submits a single `IORING_OP_ASYNC_CANCEL` SQE matched against the
    target SQE's `user_data` tag and reports the kernel's terminal
    outcome.
  - `cancel_all_by_fd(&mut IoUring, RawFd) -> io::Result<usize>` uses
    `IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_ALL` (kernel 5.19+) to
    cancel every in-flight SQE that touches the given fd.
  - `enum CancelOutcome { Cancelled, NotFound, AlreadyComplete }` maps
    the three race outcomes (`0`, `-ENOENT`, `-EALREADY`) to typed
    variants so callers route into the correct buffer reclaim path.
- Added `OpTag::Cancel` so cancel CQEs are demuxable from target CQEs
  sharing the same CQ; updated `SharedRing::reap` to flag a Cancel CQE
  as an InvalidData misuse rather than silently drop it.
- Added cross-platform UAPI constants `IORING_OP_ASYNC_CANCEL`,
  `ASYNC_CANCEL_MIN_KERNEL`, `ASYNC_CANCEL_FD_MIN_KERNEL` in
  `io_uring_common`, mirrored in the non-Linux stub.
- Stub module in `io_uring_stub.rs` returns `Unsupported` so
  cross-platform callers compile without `cfg` branching.
- Re-exported the primitive from the `io_uring` module and `CancelOutcome`
  from the crate root.
- Unit coverage:
  - `cancel_by_user_data_cancels_inflight_poll` submits a PollAdd on an
    empty pipe, cancels it, asserts `CancelOutcome::Cancelled`.
  - `cancel_by_user_data_reports_not_found_for_unknown_tag` asserts
    `-ENOENT` is folded into `NotFound`, not surfaced as an error.
  - `cancel_all_by_fd_cancels_inflight_polls` cancels two PollAdds
    bulk-by-fd (skips cleanly on kernels < 5.19).
  - `CancelOutcome::from_cqe_result` decode parity for each variant
    plus error surface for other errnos.
  - Stub mirrors assert `Unsupported` and constant parity.
@github-actions github-actions Bot added the enhancement New feature or request label May 17, 2026
oferchen added a commit that referenced this pull request May 18, 2026
) (#4278)

Adds the implementation skeleton for the hybrid daemon listener accepted
in the runtime-choice ADR: a tokio multi-thread runtime drives
TcpListener::accept while each connection is handed to the existing
synchronous worker via spawn_blocking. Default builds remain tokio-free.

- New `async-daemon` cargo feature gates the entire path.
- `crates/daemon/src/async_listener.rs` exposes `run_hybrid_listener`,
  taking an `Arc<dyn Fn>` sync worker and a shutdown flag. Unit tests
  bind on an ephemeral port and confirm accept-and-dispatch plus prompt
  shutdown work end-to-end.
- `daemon::run_async_daemon` wires the listener to the existing daemon
  config and signal-flag plumbing. The per-connection worker is a
  documented stub; production wiring to the sync session handler ships in
  the follow-up tracked under #1935 once the trigger conditions from
  `docs/design/daemon-async-runtime-choice.md` are met.
- Tokio features extended with `rt-multi-thread` and `macros` so the new
  builder path compiles alongside the existing `async` feature.
oferchen added a commit that referenced this pull request May 18, 2026
… (#4285)

Audits whether prerequisites for #1876 have landed and proposes
splitting the work into reviewable subtasks (#1876-a through e).

- #1874 (shared ring + POLL_ADD) shipped via PR #3553.
- #1937 (session ring pool) shipped via PR #4275.
- #1935 (hybrid tokio listener) shipped via PR #4278.
- No io_uring task carries id #1875; the original dependency note
  most plausibly meant the session-pool and listener work above.

Missing surface enumerated: pooled-ring constructors on the socket
adapters, daemon plumbing for SessionRingPool, sync and async worker
swaps, IORING_OP_LINK_TIMEOUT integration, and async-cancel
discipline. Trigger conditions (kernel >= 5.6, io_uring feature,
opt-in flag) and a five-step implementation plan included.
oferchen added a commit that referenced this pull request May 18, 2026
Scaffold the `IORING_OP_ASYNC_CANCEL` primitive now that the async daemon
listener (#4278), session ring pool (#4275), and per-thread rings (#4288)
have landed code paths that keep SQEs in-flight across abort decision
points. Until now, every io_uring helper followed `submit + wait + drain`
and never needed cancellation; the deferred design at
`docs/design/iouring-async-cancel.md` documented the trigger condition
this commit fulfils.

- New module `crates/fast_io/src/io_uring/cancel.rs` (Linux + `io_uring`
  feature gated):
  - `cancel_by_user_data(&mut IoUring, u64) -> io::Result<CancelOutcome>`
    submits a single `IORING_OP_ASYNC_CANCEL` SQE matched against the
    target SQE's `user_data` tag and reports the kernel's terminal
    outcome.
  - `cancel_all_by_fd(&mut IoUring, RawFd) -> io::Result<usize>` uses
    `IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_ALL` (kernel 5.19+) to
    cancel every in-flight SQE that touches the given fd.
  - `enum CancelOutcome { Cancelled, NotFound, AlreadyComplete }` maps
    the three race outcomes (`0`, `-ENOENT`, `-EALREADY`) to typed
    variants so callers route into the correct buffer reclaim path.
- Added `OpTag::Cancel` so cancel CQEs are demuxable from target CQEs
  sharing the same CQ; updated `SharedRing::reap` to flag a Cancel CQE
  as an InvalidData misuse rather than silently drop it.
- Added cross-platform UAPI constants `IORING_OP_ASYNC_CANCEL`,
  `ASYNC_CANCEL_MIN_KERNEL`, `ASYNC_CANCEL_FD_MIN_KERNEL` in
  `io_uring_common`, mirrored in the non-Linux stub.
- Stub module in `io_uring_stub.rs` returns `Unsupported` so
  cross-platform callers compile without `cfg` branching.
- Re-exported the primitive from the `io_uring` module and `CancelOutcome`
  from the crate root.
- Unit coverage:
  - `cancel_by_user_data_cancels_inflight_poll` submits a PollAdd on an
    empty pipe, cancels it, asserts `CancelOutcome::Cancelled`.
  - `cancel_by_user_data_reports_not_found_for_unknown_tag` asserts
    `-ENOENT` is folded into `NotFound`, not surfaced as an error.
  - `cancel_all_by_fd_cancels_inflight_polls` cancels two PollAdds
    bulk-by-fd (skips cleanly on kernels < 5.19).
  - `CancelOutcome::from_cqe_result` decode parity for each variant
    plus error surface for other errnos.
  - Stub mirrors assert `Unsupported` and constant parity.
oferchen added a commit that referenced this pull request May 18, 2026
) (#4278)

Adds the implementation skeleton for the hybrid daemon listener accepted
in the runtime-choice ADR: a tokio multi-thread runtime drives
TcpListener::accept while each connection is handed to the existing
synchronous worker via spawn_blocking. Default builds remain tokio-free.

- New `async-daemon` cargo feature gates the entire path.
- `crates/daemon/src/async_listener.rs` exposes `run_hybrid_listener`,
  taking an `Arc<dyn Fn>` sync worker and a shutdown flag. Unit tests
  bind on an ephemeral port and confirm accept-and-dispatch plus prompt
  shutdown work end-to-end.
- `daemon::run_async_daemon` wires the listener to the existing daemon
  config and signal-flag plumbing. The per-connection worker is a
  documented stub; production wiring to the sync session handler ships in
  the follow-up tracked under #1935 once the trigger conditions from
  `docs/design/daemon-async-runtime-choice.md` are met.
- Tokio features extended with `rt-multi-thread` and `macros` so the new
  builder path compiles alongside the existing `async` feature.
oferchen added a commit that referenced this pull request May 18, 2026
… (#4285)

Audits whether prerequisites for #1876 have landed and proposes
splitting the work into reviewable subtasks (#1876-a through e).

- #1874 (shared ring + POLL_ADD) shipped via PR #3553.
- #1937 (session ring pool) shipped via PR #4275.
- #1935 (hybrid tokio listener) shipped via PR #4278.
- No io_uring task carries id #1875; the original dependency note
  most plausibly meant the session-pool and listener work above.

Missing surface enumerated: pooled-ring constructors on the socket
adapters, daemon plumbing for SessionRingPool, sync and async worker
swaps, IORING_OP_LINK_TIMEOUT integration, and async-cancel
discipline. Trigger conditions (kernel >= 5.6, io_uring feature,
opt-in flag) and a five-step implementation plan included.
oferchen added a commit that referenced this pull request May 18, 2026
Scaffold the `IORING_OP_ASYNC_CANCEL` primitive now that the async daemon
listener (#4278), session ring pool (#4275), and per-thread rings (#4288)
have landed code paths that keep SQEs in-flight across abort decision
points. Until now, every io_uring helper followed `submit + wait + drain`
and never needed cancellation; the deferred design at
`docs/design/iouring-async-cancel.md` documented the trigger condition
this commit fulfils.

- New module `crates/fast_io/src/io_uring/cancel.rs` (Linux + `io_uring`
  feature gated):
  - `cancel_by_user_data(&mut IoUring, u64) -> io::Result<CancelOutcome>`
    submits a single `IORING_OP_ASYNC_CANCEL` SQE matched against the
    target SQE's `user_data` tag and reports the kernel's terminal
    outcome.
  - `cancel_all_by_fd(&mut IoUring, RawFd) -> io::Result<usize>` uses
    `IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_ALL` (kernel 5.19+) to
    cancel every in-flight SQE that touches the given fd.
  - `enum CancelOutcome { Cancelled, NotFound, AlreadyComplete }` maps
    the three race outcomes (`0`, `-ENOENT`, `-EALREADY`) to typed
    variants so callers route into the correct buffer reclaim path.
- Added `OpTag::Cancel` so cancel CQEs are demuxable from target CQEs
  sharing the same CQ; updated `SharedRing::reap` to flag a Cancel CQE
  as an InvalidData misuse rather than silently drop it.
- Added cross-platform UAPI constants `IORING_OP_ASYNC_CANCEL`,
  `ASYNC_CANCEL_MIN_KERNEL`, `ASYNC_CANCEL_FD_MIN_KERNEL` in
  `io_uring_common`, mirrored in the non-Linux stub.
- Stub module in `io_uring_stub.rs` returns `Unsupported` so
  cross-platform callers compile without `cfg` branching.
- Re-exported the primitive from the `io_uring` module and `CancelOutcome`
  from the crate root.
- Unit coverage:
  - `cancel_by_user_data_cancels_inflight_poll` submits a PollAdd on an
    empty pipe, cancels it, asserts `CancelOutcome::Cancelled`.
  - `cancel_by_user_data_reports_not_found_for_unknown_tag` asserts
    `-ENOENT` is folded into `NotFound`, not surfaced as an error.
  - `cancel_all_by_fd_cancels_inflight_polls` cancels two PollAdds
    bulk-by-fd (skips cleanly on kernels < 5.19).
  - `CancelOutcome::from_cqe_result` decode parity for each variant
    plus error surface for other errnos.
  - Stub mirrors assert `Unsupported` and constant parity.
@oferchen oferchen deleted the feat/daemon-async-tokio-listener-1935 branch May 19, 2026 19:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant