1- use core:: num:: niche_types:: Nanoseconds ;
2-
1+ use crate :: sys:: common:: timespec:: Timespec ;
32use crate :: time:: Duration ;
43use crate :: { fmt, io} ;
54
6- const NSEC_PER_SEC : u64 = 1_000_000_000 ;
75pub const UNIX_EPOCH : SystemTime = SystemTime { t : Timespec :: zero ( ) } ;
86#[ allow( dead_code) ] // Used for pthread condvar timeouts
97pub const TIMESPEC_MAX : libc:: timespec =
@@ -22,12 +20,6 @@ pub struct SystemTime {
2220 pub ( crate ) t : Timespec ,
2321}
2422
25- #[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
26- pub ( crate ) struct Timespec {
27- tv_sec : i64 ,
28- tv_nsec : Nanoseconds ,
29- }
30-
3123impl SystemTime {
3224 #[ cfg_attr( any( target_os = "horizon" , target_os = "hurd" ) , allow( unused) ) ]
3325 pub fn new ( tv_sec : i64 , tv_nsec : i64 ) -> Result < SystemTime , io:: Error > {
@@ -60,170 +52,6 @@ impl fmt::Debug for SystemTime {
6052 }
6153}
6254
63- impl Timespec {
64- const unsafe fn new_unchecked ( tv_sec : i64 , tv_nsec : i64 ) -> Timespec {
65- Timespec { tv_sec, tv_nsec : unsafe { Nanoseconds :: new_unchecked ( tv_nsec as u32 ) } }
66- }
67-
68- pub const fn zero ( ) -> Timespec {
69- unsafe { Self :: new_unchecked ( 0 , 0 ) }
70- }
71-
72- const fn new ( tv_sec : i64 , tv_nsec : i64 ) -> Result < Timespec , io:: Error > {
73- // On Apple OS, dates before epoch are represented differently than on other
74- // Unix platforms: e.g. 1/10th of a second before epoch is represented as `seconds=-1`
75- // and `nanoseconds=100_000_000` on other platforms, but is `seconds=0` and
76- // `nanoseconds=-900_000_000` on Apple OS.
77- //
78- // To compensate, we first detect this special case by checking if both
79- // seconds and nanoseconds are in range, and then correct the value for seconds
80- // and nanoseconds to match the common unix representation.
81- //
82- // Please note that Apple OS nonetheless accepts the standard unix format when
83- // setting file times, which makes this compensation round-trippable and generally
84- // transparent.
85- #[ cfg( target_vendor = "apple" ) ]
86- let ( tv_sec, tv_nsec) =
87- if ( tv_sec <= 0 && tv_sec > i64:: MIN ) && ( tv_nsec < 0 && tv_nsec > -1_000_000_000 ) {
88- ( tv_sec - 1 , tv_nsec + 1_000_000_000 )
89- } else {
90- ( tv_sec, tv_nsec)
91- } ;
92- if tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64 {
93- Ok ( unsafe { Self :: new_unchecked ( tv_sec, tv_nsec) } )
94- } else {
95- Err ( io:: const_error!( io:: ErrorKind :: InvalidData , "invalid timestamp" ) )
96- }
97- }
98-
99- pub fn now ( clock : libc:: clockid_t ) -> Timespec {
100- use crate :: mem:: MaybeUninit ;
101- use crate :: sys:: cvt;
102-
103- // Try to use 64-bit time in preparation for Y2038.
104- #[ cfg( all(
105- target_os = "linux" ,
106- target_env = "gnu" ,
107- target_pointer_width = "32" ,
108- not( target_arch = "riscv32" )
109- ) ) ]
110- {
111- use crate :: sys:: weak:: weak;
112-
113- // __clock_gettime64 was added to 32-bit arches in glibc 2.34,
114- // and it handles both vDSO calls and ENOSYS fallbacks itself.
115- weak ! (
116- fn __clock_gettime64(
117- clockid: libc:: clockid_t,
118- tp: * mut __timespec64,
119- ) -> libc:: c_int;
120- ) ;
121-
122- if let Some ( clock_gettime64) = __clock_gettime64. get ( ) {
123- let mut t = MaybeUninit :: uninit ( ) ;
124- cvt ( unsafe { clock_gettime64 ( clock, t. as_mut_ptr ( ) ) } ) . unwrap ( ) ;
125- let t = unsafe { t. assume_init ( ) } ;
126- return Timespec :: new ( t. tv_sec as i64 , t. tv_nsec as i64 ) . unwrap ( ) ;
127- }
128- }
129-
130- let mut t = MaybeUninit :: uninit ( ) ;
131- cvt ( unsafe { libc:: clock_gettime ( clock, t. as_mut_ptr ( ) ) } ) . unwrap ( ) ;
132- let t = unsafe { t. assume_init ( ) } ;
133- Timespec :: new ( t. tv_sec as i64 , t. tv_nsec as i64 ) . unwrap ( )
134- }
135-
136- pub fn sub_timespec ( & self , other : & Timespec ) -> Result < Duration , Duration > {
137- // When a >= b, the difference fits in u64.
138- fn sub_ge_to_unsigned ( a : i64 , b : i64 ) -> u64 {
139- debug_assert ! ( a >= b) ;
140- a. wrapping_sub ( b) . cast_unsigned ( )
141- }
142-
143- if self >= other {
144- let ( secs, nsec) = if self . tv_nsec . as_inner ( ) >= other. tv_nsec . as_inner ( ) {
145- (
146- sub_ge_to_unsigned ( self . tv_sec , other. tv_sec ) ,
147- self . tv_nsec . as_inner ( ) - other. tv_nsec . as_inner ( ) ,
148- )
149- } else {
150- // Following sequence of assertions explain why `self.tv_sec - 1` does not underflow.
151- debug_assert ! ( self . tv_nsec < other. tv_nsec) ;
152- debug_assert ! ( self . tv_sec > other. tv_sec) ;
153- debug_assert ! ( self . tv_sec > i64 :: MIN ) ;
154- (
155- sub_ge_to_unsigned ( self . tv_sec - 1 , other. tv_sec ) ,
156- self . tv_nsec . as_inner ( ) + ( NSEC_PER_SEC as u32 ) - other. tv_nsec . as_inner ( ) ,
157- )
158- } ;
159-
160- Ok ( Duration :: new ( secs, nsec) )
161- } else {
162- match other. sub_timespec ( self ) {
163- Ok ( d) => Err ( d) ,
164- Err ( d) => Ok ( d) ,
165- }
166- }
167- }
168-
169- pub fn checked_add_duration ( & self , other : & Duration ) -> Option < Timespec > {
170- let mut secs = self . tv_sec . checked_add_unsigned ( other. as_secs ( ) ) ?;
171-
172- // Nano calculations can't overflow because nanos are <1B which fit
173- // in a u32.
174- let mut nsec = other. subsec_nanos ( ) + self . tv_nsec . as_inner ( ) ;
175- if nsec >= NSEC_PER_SEC as u32 {
176- nsec -= NSEC_PER_SEC as u32 ;
177- secs = secs. checked_add ( 1 ) ?;
178- }
179- Some ( unsafe { Timespec :: new_unchecked ( secs, nsec. into ( ) ) } )
180- }
181-
182- pub fn checked_sub_duration ( & self , other : & Duration ) -> Option < Timespec > {
183- let mut secs = self . tv_sec . checked_sub_unsigned ( other. as_secs ( ) ) ?;
184-
185- // Similar to above, nanos can't overflow.
186- let mut nsec = self . tv_nsec . as_inner ( ) as i32 - other. subsec_nanos ( ) as i32 ;
187- if nsec < 0 {
188- nsec += NSEC_PER_SEC as i32 ;
189- secs = secs. checked_sub ( 1 ) ?;
190- }
191- Some ( unsafe { Timespec :: new_unchecked ( secs, nsec. into ( ) ) } )
192- }
193-
194- #[ allow( dead_code) ]
195- pub fn to_timespec ( & self ) -> Option < libc:: timespec > {
196- Some ( libc:: timespec {
197- tv_sec : self . tv_sec . try_into ( ) . ok ( ) ?,
198- tv_nsec : self . tv_nsec . as_inner ( ) . try_into ( ) . ok ( ) ?,
199- } )
200- }
201-
202- // On QNX Neutrino, the maximum timespec for e.g. pthread_cond_timedwait
203- // is 2^64 nanoseconds
204- #[ cfg( target_os = "nto" ) ]
205- pub ( in crate :: sys) fn to_timespec_capped ( & self ) -> Option < libc:: timespec > {
206- // Check if timeout in nanoseconds would fit into an u64
207- if ( self . tv_nsec . as_inner ( ) as u64 )
208- . checked_add ( ( self . tv_sec as u64 ) . checked_mul ( NSEC_PER_SEC ) ?)
209- . is_none ( )
210- {
211- return None ;
212- }
213- self . to_timespec ( )
214- }
215-
216- #[ cfg( all(
217- target_os = "linux" ,
218- target_env = "gnu" ,
219- target_pointer_width = "32" ,
220- not( target_arch = "riscv32" )
221- ) ) ]
222- pub fn to_timespec64 ( & self ) -> __timespec64 {
223- __timespec64:: new ( self . tv_sec , self . tv_nsec . as_inner ( ) as _ )
224- }
225- }
226-
22755#[ cfg( all(
22856 target_os = "linux" ,
22957 target_env = "gnu" ,
0 commit comments