Skip to content

Commit 009614c

Browse files
committed
rt: Resolve panic with large duration sleeps
Durations far into the future would cause the conversion of millis from u128 to u64 to fail and set the value to u64::MAX. This in turn causes issues since u64::MAX is used as a signal value. This patch adds a new constant that is the largest non-signal value that can be used for ticks. And uses that in the location it causes issues.
1 parent 93bde08 commit 009614c

File tree

4 files changed

+20
-3
lines changed

4 files changed

+20
-3
lines changed

tokio/src/runtime/time/entry.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ type TimerResult = Result<(), crate::time::error::Error>;
7272
const STATE_DEREGISTERED: u64 = u64::MAX;
7373
const STATE_PENDING_FIRE: u64 = STATE_DEREGISTERED - 1;
7474
const STATE_MIN_VALUE: u64 = STATE_PENDING_FIRE;
75+
/// The largest safe integer to use for ticks.
76+
///
77+
/// This value should be updated if any other signal values are added above.
78+
pub(super) const MAX_SAFE_MILLIS_DURATION: u64 = u64::MAX - 2;
7579

7680
/// This structure holds the current shared state of the timer - its scheduled
7781
/// time (if registered), or otherwise the result of the timer completing, as
@@ -126,7 +130,7 @@ impl StateCell {
126130
fn when(&self) -> Option<u64> {
127131
let cur_state = self.state.load(Ordering::Relaxed);
128132

129-
if cur_state == u64::MAX {
133+
if cur_state == STATE_DEREGISTERED {
130134
None
131135
} else {
132136
Some(cur_state)

tokio/src/runtime/time/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
99
mod entry;
1010
pub(crate) use entry::TimerEntry;
11-
use entry::{EntryList, TimerHandle, TimerShared};
11+
use entry::{EntryList, TimerHandle, TimerShared, MAX_SAFE_MILLIS_DURATION};
1212

1313
mod handle;
1414
pub(crate) use self::handle::Handle;

tokio/src/runtime/time/source.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::MAX_SAFE_MILLIS_DURATION;
12
use crate::time::{Clock, Duration, Instant};
23

34
/// A structure which handles conversion from Instants to u64 timestamps.
@@ -25,7 +26,7 @@ impl TimeSource {
2526
.unwrap_or_else(|| Duration::from_secs(0));
2627
let ms = dur.as_millis();
2728

28-
ms.try_into().unwrap_or(u64::MAX)
29+
ms.try_into().unwrap_or(MAX_SAFE_MILLIS_DURATION)
2930
}
3031

3132
pub(crate) fn tick_to_duration(&self, t: u64) -> Duration {

tokio/tests/time_sleep.rs

+12
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,18 @@ async fn exactly_max() {
267267
time::sleep(ms(MAX_DURATION)).await;
268268
}
269269

270+
#[tokio::test]
271+
async fn issue_5183() {
272+
time::pause();
273+
274+
let big = std::time::Duration::from_secs(u64::MAX / 10);
275+
// This is a workaround since awaiting sleep(big) with never finish.
276+
tokio::select! {
277+
_ = tokio::time::sleep(big) => {}
278+
_ = tokio::time::sleep(std::time::Duration::from_nanos(1)) => {}
279+
}
280+
}
281+
270282
#[tokio::test]
271283
async fn no_out_of_bounds_close_to_max() {
272284
time::pause();

0 commit comments

Comments
 (0)