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