pub async fn run_stdio<R, W>(
engine: Arc<RpcEngine>,
reader: R,
writer: W,
) -> Result<()>Expand description
Drive the JSONL-RPC protocol over reader/writer (the stdio rung —
parent-process-trusted, no auth token; see the module doc). Each
request line is dispatched on its OWN spawned task so a submit
in-flight never blocks the reader from picking up a subsequent
interrupt/status line — every outgoing line (a response OR an event
notification) is funneled through one mpsc channel into a single writer
task, so two concurrent handlers can never interleave a line’s bytes.
Returns once reader hits EOF or a shutdown request lands.
Both termination paths raise RpcEngine::signal_shutdown (EOF does it
directly here; the shutdown RPC does it inside
RpcEngine::handle_shutdown), and event_task below SELECTS against
RpcEngine::wait_for_shutdown rather than merely looping on
events.recv(). This is deliberate: events.recv() alone only ends via
RecvError::Closed, which fires only once EVERY clone of
engine.events (the broadcast Sender) has dropped — and engine
itself, which keeps that Sender alive, is owned by THIS function for
its whole body. Waiting on events.recv() to close would therefore mean
waiting on engine to drop, which can’t happen until event_task
itself finishes — a circular wait that never resolves (the bug this fn
exists to fix). Selecting on the shutdown signal instead lets
event_task end WITHOUT needing engine’s refcount to reach zero, so
there is no orphaned task and no leaked engine/writer_task blocking
on it in turn.