pub async fn timeout<F: Future>(
duration: Duration,
fut: F,
) -> Result<F::Output, Elapsed>Expand description
Await fut, giving up after duration — the seam’s only bounded wait.
It belongs here rather than at the call sites for the same reason sleep
does: a deadline needs a timer, and which timer that is depends on the
backend and on the calling thread. Call sites that reach for
tokio::time::timeout directly pin themselves to the tokio timer wheel,
which exists on one backend and only inside a runtime.
A budget under SIGNIFICANT_DELAY never reaches a timer at all. It cannot:
a timeout polls the inner future first and only then arms its sleep, and a
zero-length sleep is not reported elapsed until the time driver next runs — so on a loaded machine the inner future wins a race that
C does not have, and an already-expired -w returns success. Measured as
caget -w -1 exiting 0 where C exits 1
(tool_lib.c:628-638 via ca_client_context.cpp:490-499).
One body for both backends, raced against sleep, because the backend was
never the question a bounded wait had to ask. The hosted half called
tokio::time::timeout, which panics on a thread with no runtime, so the
seam had a deadline the exec backend honoured for every caller and the
hosted one honoured only inside a runtime. Callers had no way to express
that difference and did not try to: asyn-rs’s PortHandle::await_reply
simply lost its queue_timeout on every plain-thread submit_blocking.
sleep now picks a timer the calling thread can reach, so the race below
fires wherever it is polled.