pausable-tokio
A fork of tokio that adds a runtime- controllable pause/resume primitive on top of its clock.
When the runtime is built with Builder::pausable_time, its notion of
time is backed by pausable_clock and can be paused or resumed at any
moment by calling methods on the Runtime. Sleeps, intervals,
timeouts, and anything else that uses tokio's clock will not advance
while the runtime is paused.
The rest of the tokio API is unchanged, so pausable-tokio is a
drop-in replacement: most code only needs a one-line Cargo.toml
change.
When to use this
- Building a simulator or game loop where you want the entire async system to halt when the user pauses, without threading "is paused" through every async function.
- Snapshot-and-resume of a long-running async system.
- Diagnostic tooling that needs to freeze a running runtime to take a consistent measurement.
- Production code that needs real pause/resume rather than the
test-only
tokio::time::pause(which requirestest-utiland the current-thread runtime).
Quick start
Add to your Cargo.toml. Renaming the dependency to tokio lets you
keep using tokio::... paths everywhere; the rest of your code does
not need to change.
[]
= { = "pausable-tokio", = "1.52.1", = ["full"] }
Then enable pausable time on the runtime builder, and pause/resume whenever you like:
use Arc;
use thread;
use Duration;
use Builder;
API additions
pausable-tokio adds a few methods to Builder and Runtime.
Everything else is identical to upstream tokio.
| Method | What it does |
|---|---|
Builder::pausable_time(start_paused, elapsed_time) |
Enable the pausable clock when constructing the runtime. elapsed_time is a starting offset for Runtime::elapsed_millis. |
Runtime::pause() |
Pause the clock. Returns true if it actually flipped the state. |
Runtime::resume() |
Resume the clock. Returns true if it actually flipped the state. |
Runtime::is_paused() / is_paused_ordered(Ordering) |
Query whether the clock is paused. |
Runtime::wait_for_pause() / wait_for_resume() |
Block the calling thread until the clock changes state. |
Runtime::run_unpausable(f) |
Run a closure while preventing the clock from being paused (used internally to wrap every task poll). |
Runtime::run_unresumable(f) |
Mirror of the above for the resumed-state side. |
Runtime::run_if_paused(f) / run_if_resumed(f) |
Atomic conditional run. |
Runtime::now() |
The runtime's notion of the current Instant. |
Runtime::elapsed_millis() |
Elapsed time on the pausable clock, in milliseconds. |
Differences from tokio::time::pause
pausable-tokio |
upstream tokio::time::pause |
|
|---|---|---|
| Feature gate | time (default in full) |
test-util |
| Intended use | Production | Tests |
| Schedulers supported | both current-thread and multi-thread | current-thread only |
| Behavior while paused | clock literally stops | "auto-advance" jumps time forward to next pending sleep |
| Driven from | any thread, any time | only via tokio::time::* API |
Source / how this is built
pausable-tokio is generated by applying a small set of patches to
upstream tokio at a specific release tag. The patches and the workflow
are at https://github.com/RookAndPawn/pausable-tokio; see that repo
if you want to update the upstream base or contribute to the fork.
License
MIT, same as upstream tokio.