Never Snooze a Future
6 days ago
- #deadlocks
- #async-rust
- #futures
- Snoozing in async Rust refers to a future that's ready to make progress but isn't being polled, leading to hangs and deadlocks.
- Snoozing is distinct from cancellation and starvation, representing a bug where a future that requested a wakeup doesn't get polled.
- Deadlocks ('futurelocks') are a clear consequence of snoozing, where a task stops polling a future it previously started, causing system hangs.
- Examples include scenarios with `select!` by reference and buffered streams, where internal futures are snoozed, leading to deadlocks.
- Thread cancellation in synchronous programming contrasts with future cancellation in async Rust, where Rust's drop mechanism allows cleaner resource cleanup.
- Snoozing a future is akin to pausing a thread, risking deadlocks when the paused entity holds locks needed by other parts of the system.
- Solutions to avoid snoozing include avoiding `select!` with references, using owned futures, and considering alternative patterns like `join_me_maybe`.
- Stream methods like `.next()` and buffered streams pose snoozing risks, suggesting a need for clearer cancel safety definitions and possibly deprecating problematic patterns.
- A proposed rule to prevent snoozing is to avoid pinning things in async functions, as pinning often indicates polling a future that isn't owned.
- Advanced async Rust (implementing `Future` or `Stream`) requires careful review to ensure snooze-free behavior, emphasizing the principle: never snooze a future.