Rollup merge of #150842 - PaulDance:patches/fix-win7-sleep, r=Mark-Simulacrum

Fix(lib/win/thread): Ensure `Sleep`'s usage passes over the requested duration under Win7

Fixes rust-lang/rust#149935. See the added comment for more details.

This makes the concerned test now reproducibly pass, for us at least. Also, testing this separately revealed successful: see the issue.

@rustbot label C-bug I-flaky-test O-windows-7 T-libs A-time A-thread
This commit is contained in:
Matthias Krüger 2026-01-25 07:42:59 +01:00 committed by GitHub
commit 38504731be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -8,7 +8,7 @@ use crate::sys::pal::time::WaitableTimer;
use crate::sys::pal::{dur2timeout, to_u16s};
use crate::sys::{FromInner, c, stack_overflow};
use crate::thread::ThreadInit;
use crate::time::Duration;
use crate::time::{Duration, Instant};
use crate::{io, ptr};
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@ -120,11 +120,28 @@ pub fn sleep(dur: Duration) {
timer.set(dur)?;
timer.wait()
}
// Directly forward to `Sleep` for its zero duration behavior when indeed
// zero in order to skip the `Instant::now` calls, useless in this case.
if dur.is_zero() {
unsafe { c::Sleep(0) };
// Attempt to use high-precision sleep (Windows 10, version 1803+).
// On error fallback to the standard `Sleep` function.
// Also preserves the zero duration behavior of `Sleep`.
if dur.is_zero() || high_precision_sleep(dur).is_err() {
unsafe { c::Sleep(dur2timeout(dur)) }
// On error, fallback to the standard `Sleep` function.
} else if high_precision_sleep(dur).is_err() {
let start = Instant::now();
unsafe { c::Sleep(dur2timeout(dur)) };
// See #149935: `Sleep` under Windows 7 and probably 8 as well seems a
// bit buggy for us as it can last less than the requested time while
// our API is meant to guarantee that. This is fixed by measuring the
// effective time difference and if needed, sleeping a bit more in
// order to ensure the duration is always exceeded. A fixed single
// millisecond works because `Sleep` operates based on a system-wide
// (until Windows 10 2004 that makes it process-local) interrupt timer
// that counts in "tick" units of ~15ms by default: a 1ms timeout
// therefore passes the next tick boundary.
if start.elapsed() < dur {
unsafe { c::Sleep(1) };
}
}
}