Skip to content

The thread::sleep_until test frequently fails under Windows 7 #149935

@PaulDance

Description

@PaulDance

As part of our (lately subpar) maintenance of the Windows 7 target, we run the library's tests. Since 1.90 while building for stable, we have noticed that the library/std/tests/thread.rs::sleep_until test started to fail quite frequently.

The test itself is quite simple:

fn sleep_until() {
let now = Instant::now();
let period = Duration::from_millis(100);
let deadline = now + period;
thread::sleep_until(deadline);
let elapsed = now.elapsed();
assert!(elapsed >= period);
}

and fails on assertion misses such as:

running 1 test
[.../lib.rs:125:9] elapsed = 95.9499ms
[.../lib.rs:125:9] period = 100ms

thread 'tests::sleep_until' panicked at [...]/lib.rs:126:9:
assertion failed: elapsed >= period
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
test tests::sleep_until ... FAILED

These errors are appropriate, but there is still something not quite right somewhere.

The current implementation of sleep_until under Windows is still a proxy to sleep(deadline - Instant::now()) if I'm not mistaken, so the issue could come from sleep itself. In fact, the issue can also be reproduced with the slightly simpler:

#[test]
fn sleep() {
    let now = Instant::now();
    let period = Duration::from_millis(100);
    thread::sleep(period);

    let elapsed = now.elapsed();
    dbg!(elapsed, period);
    assert!(elapsed >= period);
}

Under Windows 7, the high precision timer API is not available, so the standard Sleep function gets used with the given Duration's milliseconds. On the one hand, Rust's thread::sleep documents that "It will never sleep less [than the duration specified].", while on the other hand Window's Sleep only documents that "The system clock 'ticks' at a constant rate. If dwMilliseconds is less than the resolution of the system clock, the thread may sleep for less than the specified length of time. If dwMilliseconds is greater than one tick but less than two, the wait can be anywhere between one and two ticks, and so on.", but not more specifically that it assuringly cannot suspend for less than the specified length of time. Trying to get or set the "accuracy of the sleep interval" using the recommended methods for example to be 1ms did not help. Could it be that Windows 7's implementation of the function is just not that precise anyway?

The test actually has two facets: sleeping and measuring time. The latter could also be the cause of the errors here. As documented and implemented, the Instant::now bases itself on QueryPerformanceCounter under Windows. The function itself does not document much, but "Acquiring high-resolution time stamps" gives some lower-level details. Among these, it does mention a high adherence to hardware features. Could it therefore be the cause here? We use QEMU for running Windows 7 in VMs. I have tried to enable as much hardware-related options of QEMU to see if it could fix the problem, but it was to no avail. If it is indeed the cause, it is more a Windows 7 or QEMU issue?

We are having trouble answering these questions ourselves. Does anyone know what could be happening here? In particular, is it something that will never realistically work under Windows 7 or the testing facilities we use, while under actual hardware there would be no issue, and so the test should be simply ignored?

Note that I can reproduce these errors under our 1.89 build already, so considering the test landed in stable under 1.90, the issue might not be recent. Also, although it might be obvious, I cannot reproduce this under Windows 10+. This could only be a testing issue, so I'm not tagging this as a bug just yet.

cc @roblabla

@rustbot label F-sleep_until O-windows-7 T-libs I-flaky-test A-time A-thread E-help-wanted

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-threadArea: `std::thread`A-timeArea: TimeE-help-wantedCall for participation: Help is requested to fix this issue.F-sleep_until`#![feature(sleep_until)]`I-flaky-testIssue: A test is flaky/unreliable/spuriously failsO-windows-7OS: Windows 7 or Windows Server 2008 R2 or etc.T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions