1- use core:: hash:: { Hash , Hasher } ;
2- use core:: ops:: Neg ;
3-
4- use crate :: cmp:: Ordering ;
1+ use crate :: ops:: Neg ;
52use crate :: ptr:: null;
6- use crate :: sys:: { IntoInner , c } ;
3+ use crate :: sys:: pal :: c ;
74use crate :: time:: Duration ;
8- use crate :: { fmt, mem} ;
95
106const NANOS_PER_SEC : u64 = 1_000_000_000 ;
11- const INTERVALS_PER_SEC : u64 = NANOS_PER_SEC / 100 ;
12-
13- #[ derive( Copy , Clone , Eq , PartialEq , Ord , PartialOrd , Debug , Hash ) ]
14- pub struct Instant {
15- // This duration is relative to an arbitrary microsecond epoch
16- // from the winapi QueryPerformanceCounter function.
17- t : Duration ,
18- }
19-
20- #[ derive( Copy , Clone ) ]
21- pub struct SystemTime {
22- t : c:: FILETIME ,
23- }
24-
25- const INTERVALS_TO_UNIX_EPOCH : u64 = 11_644_473_600 * INTERVALS_PER_SEC ;
26-
27- pub const UNIX_EPOCH : SystemTime = SystemTime {
28- t : c:: FILETIME {
29- dwLowDateTime : INTERVALS_TO_UNIX_EPOCH as u32 ,
30- dwHighDateTime : ( INTERVALS_TO_UNIX_EPOCH >> 32 ) as u32 ,
31- } ,
32- } ;
33-
34- impl Instant {
35- pub fn now ( ) -> Instant {
36- // High precision timing on windows operates in "Performance Counter"
37- // units, as returned by the WINAPI QueryPerformanceCounter function.
38- // These relate to seconds by a factor of QueryPerformanceFrequency.
39- // In order to keep unit conversions out of normal interval math, we
40- // measure in QPC units and immediately convert to nanoseconds.
41- perf_counter:: PerformanceCounterInstant :: now ( ) . into ( )
42- }
43-
44- pub fn checked_sub_instant ( & self , other : & Instant ) -> Option < Duration > {
45- // On windows there's a threshold below which we consider two timestamps
46- // equivalent due to measurement error. For more details + doc link,
47- // check the docs on epsilon.
48- let epsilon = perf_counter:: PerformanceCounterInstant :: epsilon ( ) ;
49- if other. t > self . t && other. t - self . t <= epsilon {
50- Some ( Duration :: new ( 0 , 0 ) )
51- } else {
52- self . t . checked_sub ( other. t )
53- }
54- }
55-
56- pub fn checked_add_duration ( & self , other : & Duration ) -> Option < Instant > {
57- Some ( Instant { t : self . t . checked_add ( * other) ? } )
58- }
59-
60- pub fn checked_sub_duration ( & self , other : & Duration ) -> Option < Instant > {
61- Some ( Instant { t : self . t . checked_sub ( * other) ? } )
62- }
63- }
64-
65- impl SystemTime {
66- pub const MAX : SystemTime = SystemTime {
67- t : c:: FILETIME {
68- dwLowDateTime : ( i64:: MAX & 0xFFFFFFFF ) as u32 ,
69- dwHighDateTime : ( i64:: MAX >> 32 ) as u32 ,
70- } ,
71- } ;
72-
73- pub const MIN : SystemTime =
74- SystemTime { t : c:: FILETIME { dwLowDateTime : 0 , dwHighDateTime : 0 } } ;
75-
76- pub fn now ( ) -> SystemTime {
77- unsafe {
78- let mut t: SystemTime = mem:: zeroed ( ) ;
79- c:: GetSystemTimePreciseAsFileTime ( & mut t. t ) ;
80- t
81- }
82- }
83-
84- fn from_intervals ( intervals : i64 ) -> SystemTime {
85- SystemTime {
86- t : c:: FILETIME {
87- dwLowDateTime : intervals as u32 ,
88- dwHighDateTime : ( intervals >> 32 ) as u32 ,
89- } ,
90- }
91- }
92-
93- fn intervals ( & self ) -> i64 {
94- ( self . t . dwLowDateTime as i64 ) | ( ( self . t . dwHighDateTime as i64 ) << 32 )
95- }
96-
97- pub fn sub_time ( & self , other : & SystemTime ) -> Result < Duration , Duration > {
98- let me = self . intervals ( ) ;
99- let other = other. intervals ( ) ;
100- if me >= other {
101- Ok ( intervals2dur ( ( me - other) as u64 ) )
102- } else {
103- Err ( intervals2dur ( ( other - me) as u64 ) )
104- }
105- }
106-
107- pub fn checked_add_duration ( & self , other : & Duration ) -> Option < SystemTime > {
108- let intervals = self . intervals ( ) . checked_add ( checked_dur2intervals ( other) ?) ?;
109- Some ( SystemTime :: from_intervals ( intervals) )
110- }
111-
112- pub fn checked_sub_duration ( & self , other : & Duration ) -> Option < SystemTime > {
113- // Windows does not support times before 1601, hence why we don't
114- // support negatives. In order to tackle this, we try to convert the
115- // resulting value into an u64, which should obviously fail in the case
116- // that the value is below zero.
117- let intervals: u64 =
118- self . intervals ( ) . checked_sub ( checked_dur2intervals ( other) ?) ?. try_into ( ) . ok ( ) ?;
119- Some ( SystemTime :: from_intervals ( intervals as i64 ) )
120- }
121- }
122-
123- impl PartialEq for SystemTime {
124- fn eq ( & self , other : & SystemTime ) -> bool {
125- self . intervals ( ) == other. intervals ( )
126- }
127- }
128-
129- impl Eq for SystemTime { }
130-
131- impl PartialOrd for SystemTime {
132- fn partial_cmp ( & self , other : & SystemTime ) -> Option < Ordering > {
133- Some ( self . cmp ( other) )
134- }
135- }
7+ pub const INTERVALS_PER_SEC : u64 = NANOS_PER_SEC / 100 ;
1368
137- impl Ord for SystemTime {
138- fn cmp ( & self , other : & SystemTime ) -> Ordering {
139- self . intervals ( ) . cmp ( & other. intervals ( ) )
140- }
141- }
142-
143- impl fmt:: Debug for SystemTime {
144- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
145- f. debug_struct ( "SystemTime" ) . field ( "intervals" , & self . intervals ( ) ) . finish ( )
146- }
147- }
148-
149- impl From < c:: FILETIME > for SystemTime {
150- fn from ( t : c:: FILETIME ) -> SystemTime {
151- SystemTime { t }
152- }
153- }
154-
155- impl IntoInner < c:: FILETIME > for SystemTime {
156- fn into_inner ( self ) -> c:: FILETIME {
157- self . t
158- }
159- }
160-
161- impl Hash for SystemTime {
162- fn hash < H : Hasher > ( & self , state : & mut H ) {
163- self . intervals ( ) . hash ( state)
164- }
165- }
166-
167- fn checked_dur2intervals ( dur : & Duration ) -> Option < i64 > {
9+ pub fn checked_dur2intervals ( dur : & Duration ) -> Option < i64 > {
16810 dur. as_secs ( )
16911 . checked_mul ( INTERVALS_PER_SEC ) ?
17012 . checked_add ( dur. subsec_nanos ( ) as u64 / 100 ) ?
17113 . try_into ( )
17214 . ok ( )
17315}
17416
175- fn intervals2dur ( intervals : u64 ) -> Duration {
17+ pub fn intervals2dur ( intervals : u64 ) -> Duration {
17618 Duration :: new ( intervals / INTERVALS_PER_SEC , ( ( intervals % INTERVALS_PER_SEC ) * 100 ) as u32 )
17719}
17820
179- mod perf_counter {
21+ pub mod perf_counter {
18022 use super :: NANOS_PER_SEC ;
18123 use crate :: sync:: atomic:: { Atomic , AtomicU64 , Ordering } ;
182- use crate :: sys:: helpers:: mul_div_u64;
18324 use crate :: sys:: { c, cvt} ;
18425 use crate :: time:: Duration ;
18526
186- pub struct PerformanceCounterInstant {
187- ts : i64 ,
188- }
189- impl PerformanceCounterInstant {
190- pub fn now ( ) -> Self {
191- Self { ts : query ( ) }
192- }
193-
194- // Per microsoft docs, the margin of error for cross-thread time comparisons
195- // using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency().
196- // Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo
197- // /acquiring-high-resolution-time-stamps
198- pub fn epsilon ( ) -> Duration {
199- let epsilon = NANOS_PER_SEC / ( frequency ( ) as u64 ) ;
200- Duration :: from_nanos ( epsilon)
201- }
202- }
203- impl From < PerformanceCounterInstant > for super :: Instant {
204- fn from ( other : PerformanceCounterInstant ) -> Self {
205- let freq = frequency ( ) as u64 ;
206- let instant_nsec = mul_div_u64 ( other. ts as u64 , NANOS_PER_SEC , freq) ;
207- Self { t : Duration :: from_nanos ( instant_nsec) }
208- }
27+ pub fn now ( ) -> i64 {
28+ let mut qpc_value: i64 = 0 ;
29+ cvt ( unsafe { c:: QueryPerformanceCounter ( & mut qpc_value) } ) . unwrap ( ) ;
30+ qpc_value
20931 }
21032
211- fn frequency ( ) -> i64 {
33+ pub fn frequency ( ) -> i64 {
21234 // Either the cached result of `QueryPerformanceFrequency` or `0` for
21335 // uninitialized. Storing this as a single `AtomicU64` allows us to use
21436 // `Relaxed` operations, as we are only interested in the effects on a
@@ -230,17 +52,21 @@ mod perf_counter {
23052 frequency
23153 }
23254
233- fn query ( ) -> i64 {
234- let mut qpc_value: i64 = 0 ;
235- cvt ( unsafe { c:: QueryPerformanceCounter ( & mut qpc_value) } ) . unwrap ( ) ;
236- qpc_value
55+ // Per microsoft docs, the margin of error for cross-thread time comparisons
56+ // using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency().
57+ // Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo
58+ // /acquiring-high-resolution-time-stamps
59+ pub fn epsilon ( ) -> Duration {
60+ let epsilon = NANOS_PER_SEC / ( frequency ( ) as u64 ) ;
61+ Duration :: from_nanos ( epsilon)
23762 }
23863}
23964
24065/// A timer you can wait on.
24166pub ( crate ) struct WaitableTimer {
24267 handle : c:: HANDLE ,
24368}
69+
24470impl WaitableTimer {
24571 /// Creates a high-resolution timer. Will fail before Windows 10, version 1803.
24672 pub fn high_resolution ( ) -> Result < Self , ( ) > {
@@ -254,6 +80,7 @@ impl WaitableTimer {
25480 } ;
25581 if !handle. is_null ( ) { Ok ( Self { handle } ) } else { Err ( ( ) ) }
25682 }
83+
25784 pub fn set ( & self , duration : Duration ) -> Result < ( ) , ( ) > {
25885 // Convert the Duration to a format similar to FILETIME.
25986 // Negative values are relative times whereas positive values are absolute.
@@ -262,11 +89,13 @@ impl WaitableTimer {
26289 let result = unsafe { c:: SetWaitableTimer ( self . handle , & time, 0 , None , null ( ) , c:: FALSE ) } ;
26390 if result != 0 { Ok ( ( ) ) } else { Err ( ( ) ) }
26491 }
92+
26593 pub fn wait ( & self ) -> Result < ( ) , ( ) > {
26694 let result = unsafe { c:: WaitForSingleObject ( self . handle , c:: INFINITE ) } ;
26795 if result != c:: WAIT_FAILED { Ok ( ( ) ) } else { Err ( ( ) ) }
26896 }
26997}
98+
27099impl Drop for WaitableTimer {
271100 fn drop ( & mut self ) {
272101 unsafe { c:: CloseHandle ( self . handle ) } ;
0 commit comments