about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/std/src/sys/windows/c/windows_sys.lst6
-rw-r--r--library/std/src/sys/windows/c/windows_sys.rs32
-rw-r--r--library/std/src/sys/windows/thread.rs13
-rw-r--r--library/std/src/sys/windows/time.rs38
4 files changed, 88 insertions, 1 deletions
diff --git a/library/std/src/sys/windows/c/windows_sys.lst b/library/std/src/sys/windows/c/windows_sys.lst
index 0aca37e2d45..9aabac32211 100644
--- a/library/std/src/sys/windows/c/windows_sys.lst
+++ b/library/std/src/sys/windows/c/windows_sys.lst
@@ -2503,9 +2503,12 @@ Windows.Win32.System.Threading.CREATE_SEPARATE_WOW_VDM
 Windows.Win32.System.Threading.CREATE_SHARED_WOW_VDM
 Windows.Win32.System.Threading.CREATE_SUSPENDED
 Windows.Win32.System.Threading.CREATE_UNICODE_ENVIRONMENT
+Windows.Win32.System.Threading.CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
+Windows.Win32.System.Threading.CREATE_WAITABLE_TIMER_MANUAL_RESET
 Windows.Win32.System.Threading.CreateEventW
 Windows.Win32.System.Threading.CreateProcessW
 Windows.Win32.System.Threading.CreateThread
+Windows.Win32.System.Threading.CreateWaitableTimerExW
 Windows.Win32.System.Threading.DEBUG_ONLY_THIS_PROCESS
 Windows.Win32.System.Threading.DEBUG_PROCESS
 Windows.Win32.System.Threading.DeleteProcThreadAttributeList
@@ -2542,6 +2545,7 @@ Windows.Win32.System.Threading.REALTIME_PRIORITY_CLASS
 Windows.Win32.System.Threading.ReleaseSRWLockExclusive
 Windows.Win32.System.Threading.ReleaseSRWLockShared
 Windows.Win32.System.Threading.SetThreadStackGuarantee
+Windows.Win32.System.Threading.SetWaitableTimer
 Windows.Win32.System.Threading.Sleep
 Windows.Win32.System.Threading.SleepConditionVariableSRW
 Windows.Win32.System.Threading.SleepEx
@@ -2568,6 +2572,8 @@ Windows.Win32.System.Threading.TerminateProcess
 Windows.Win32.System.Threading.THREAD_CREATE_RUN_IMMEDIATELY
 Windows.Win32.System.Threading.THREAD_CREATE_SUSPENDED
 Windows.Win32.System.Threading.THREAD_CREATION_FLAGS
+Windows.Win32.System.Threading.TIMER_ALL_ACCESS
+Windows.Win32.System.Threading.TIMER_MODIFY_STATE
 Windows.Win32.System.Threading.TLS_OUT_OF_INDEXES
 Windows.Win32.System.Threading.TlsAlloc
 Windows.Win32.System.Threading.TlsFree
diff --git a/library/std/src/sys/windows/c/windows_sys.rs b/library/std/src/sys/windows/c/windows_sys.rs
index 851d15915c7..a22854367be 100644
--- a/library/std/src/sys/windows/c/windows_sys.rs
+++ b/library/std/src/sys/windows/c/windows_sys.rs
@@ -152,6 +152,15 @@ extern "system" {
 }
 #[link(name = "kernel32")]
 extern "system" {
+    pub fn CreateWaitableTimerExW(
+        lptimerattributes: *const SECURITY_ATTRIBUTES,
+        lptimername: PCWSTR,
+        dwflags: u32,
+        dwdesiredaccess: u32,
+    ) -> HANDLE;
+}
+#[link(name = "kernel32")]
+extern "system" {
     pub fn DeleteFileW(lpfilename: PCWSTR) -> BOOL;
 }
 #[link(name = "kernel32")]
@@ -509,6 +518,17 @@ extern "system" {
 }
 #[link(name = "kernel32")]
 extern "system" {
+    pub fn SetWaitableTimer(
+        htimer: HANDLE,
+        lpduetime: *const i64,
+        lperiod: i32,
+        pfncompletionroutine: PTIMERAPCROUTINE,
+        lpargtocompletionroutine: *const ::core::ffi::c_void,
+        fresume: BOOL,
+    ) -> BOOL;
+}
+#[link(name = "kernel32")]
+extern "system" {
     pub fn Sleep(dwmilliseconds: u32) -> ();
 }
 #[link(name = "kernel32")]
@@ -1164,6 +1184,8 @@ pub const CREATE_SEPARATE_WOW_VDM: PROCESS_CREATION_FLAGS = 2048u32;
 pub const CREATE_SHARED_WOW_VDM: PROCESS_CREATION_FLAGS = 4096u32;
 pub const CREATE_SUSPENDED: PROCESS_CREATION_FLAGS = 4u32;
 pub const CREATE_UNICODE_ENVIRONMENT: PROCESS_CREATION_FLAGS = 1024u32;
+pub const CREATE_WAITABLE_TIMER_HIGH_RESOLUTION: u32 = 2u32;
+pub const CREATE_WAITABLE_TIMER_MANUAL_RESET: u32 = 1u32;
 pub const CSTR_EQUAL: COMPARESTRING_RESULT = 2i32;
 pub const CSTR_GREATER_THAN: COMPARESTRING_RESULT = 3i32;
 pub const CSTR_LESS_THAN: COMPARESTRING_RESULT = 1i32;
@@ -3774,6 +3796,13 @@ pub const PROFILE_SERVER: PROCESS_CREATION_FLAGS = 1073741824u32;
 pub const PROFILE_USER: PROCESS_CREATION_FLAGS = 268435456u32;
 pub const PROGRESS_CONTINUE: u32 = 0u32;
 pub type PSTR = *mut u8;
+pub type PTIMERAPCROUTINE = ::core::option::Option<
+    unsafe extern "system" fn(
+        lpargtocompletionroutine: *const ::core::ffi::c_void,
+        dwtimerlowvalue: u32,
+        dwtimerhighvalue: u32,
+    ) -> (),
+>;
 pub type PWSTR = *mut u16;
 pub const READ_CONTROL: FILE_ACCESS_RIGHTS = 131072u32;
 pub const REALTIME_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 256u32;
@@ -3910,6 +3939,7 @@ pub type SYMBOLIC_LINK_FLAGS = u32;
 pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: SYMBOLIC_LINK_FLAGS = 2u32;
 pub const SYMBOLIC_LINK_FLAG_DIRECTORY: SYMBOLIC_LINK_FLAGS = 1u32;
 pub const SYMLINK_FLAG_RELATIVE: u32 = 1u32;
+pub type SYNCHRONIZATION_ACCESS_RIGHTS = u32;
 pub const SYNCHRONIZE: FILE_ACCESS_RIGHTS = 1048576u32;
 #[repr(C)]
 pub struct SYSTEM_INFO {
@@ -3956,6 +3986,8 @@ pub const TCP_NODELAY: i32 = 1i32;
 pub const THREAD_CREATE_RUN_IMMEDIATELY: THREAD_CREATION_FLAGS = 0u32;
 pub const THREAD_CREATE_SUSPENDED: THREAD_CREATION_FLAGS = 4u32;
 pub type THREAD_CREATION_FLAGS = u32;
+pub const TIMER_ALL_ACCESS: SYNCHRONIZATION_ACCESS_RIGHTS = 2031619u32;
+pub const TIMER_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32;
 #[repr(C)]
 pub struct TIMEVAL {
     pub tv_sec: i32,
diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs
index 18cecb65681..4117760dae3 100644
--- a/library/std/src/sys/windows/thread.rs
+++ b/library/std/src/sys/windows/thread.rs
@@ -12,6 +12,7 @@ use crate::time::Duration;
 
 use libc::c_void;
 
+use super::time::WaitableTimer;
 use super::to_u16s;
 
 pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@@ -87,7 +88,17 @@ impl Thread {
     }
 
     pub fn sleep(dur: Duration) {
-        unsafe { c::Sleep(super::dur2timeout(dur)) }
+        fn high_precision_sleep(dur: Duration) -> Result<(), ()> {
+            let timer = WaitableTimer::high_resolution()?;
+            timer.set(dur)?;
+            timer.wait()
+        }
+        // Attempt to use high-precision sleep (Windows 10, version 1803+).
+        // On error fallback to the standard `Sleep` function.
+        // Also preserves the zero duration behaviour of `Sleep`.
+        if dur.is_zero() || high_precision_sleep(dur).is_err() {
+            unsafe { c::Sleep(super::dur2timeout(dur)) }
+        }
     }
 
     pub fn handle(&self) -> &Handle {
diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs
index b8209a85445..bece48e799f 100644
--- a/library/std/src/sys/windows/time.rs
+++ b/library/std/src/sys/windows/time.rs
@@ -1,11 +1,13 @@
 use crate::cmp::Ordering;
 use crate::fmt;
 use crate::mem;
+use crate::ptr::{null, null_mut};
 use crate::sys::c;
 use crate::sys_common::IntoInner;
 use crate::time::Duration;
 
 use core::hash::{Hash, Hasher};
+use core::ops::Neg;
 
 const NANOS_PER_SEC: u64 = 1_000_000_000;
 const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100;
@@ -222,3 +224,39 @@ mod perf_counter {
         qpc_value
     }
 }
+
+/// A timer you can wait on.
+pub(super) struct WaitableTimer {
+    handle: c::HANDLE,
+}
+impl WaitableTimer {
+    /// Create a high-resolution timer. Will fail before Windows 10, version 1803.
+    pub fn high_resolution() -> Result<Self, ()> {
+        let handle = unsafe {
+            c::CreateWaitableTimerExW(
+                null(),
+                null(),
+                c::CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
+                c::TIMER_ALL_ACCESS,
+            )
+        };
+        if handle != null_mut() { Ok(Self { handle }) } else { Err(()) }
+    }
+    pub fn set(&self, duration: Duration) -> Result<(), ()> {
+        // Convert the Duration to a format similar to FILETIME.
+        // Negative values are relative times whereas positive values are absolute.
+        // Therefore we negate the relative duration.
+        let time = checked_dur2intervals(&duration).ok_or(())?.neg();
+        let result = unsafe { c::SetWaitableTimer(self.handle, &time, 0, None, null(), c::FALSE) };
+        if result != 0 { Ok(()) } else { Err(()) }
+    }
+    pub fn wait(&self) -> Result<(), ()> {
+        let result = unsafe { c::WaitForSingleObject(self.handle, c::INFINITE) };
+        if result != c::WAIT_FAILED { Ok(()) } else { Err(()) }
+    }
+}
+impl Drop for WaitableTimer {
+    fn drop(&mut self) {
+        unsafe { c::CloseHandle(self.handle) };
+    }
+}