1use errno::{set_errno, Errno};
2use libc::{c_int, c_uint};
3
4use crate::convert_res;
5
6fn rustix_timespec_to_libc_timespec(
7 rustix_time: rustix::time::Timespec,
8) -> Result<libc::timespec, core::num::TryFromIntError> {
9 let mut time: libc::timespec = unsafe { core::mem::zeroed() };
11 time.tv_sec = rustix_time.tv_sec.try_into()?;
12 time.tv_nsec = rustix_time.tv_nsec.try_into()?;
13 Ok(time)
14}
15
16#[no_mangle]
17unsafe extern "C" fn clock_gettime(id: c_int, tp: *mut libc::timespec) -> c_int {
18 libc!(libc::clock_gettime(id, tp));
19
20 let id = match id {
21 libc::CLOCK_MONOTONIC => {
22 rustix::time::DynamicClockId::Known(rustix::time::ClockId::Monotonic)
23 }
24 libc::CLOCK_REALTIME => {
25 rustix::time::DynamicClockId::Known(rustix::time::ClockId::Realtime)
26 }
27 libc::CLOCK_BOOTTIME => rustix::time::DynamicClockId::Boottime,
28 libc::CLOCK_MONOTONIC_COARSE => {
29 rustix::time::DynamicClockId::Known(rustix::time::ClockId::MonotonicCoarse)
30 }
31 libc::CLOCK_REALTIME_COARSE => {
32 rustix::time::DynamicClockId::Known(rustix::time::ClockId::RealtimeCoarse)
33 }
34 libc::CLOCK_MONOTONIC_RAW => {
35 rustix::time::DynamicClockId::Known(rustix::time::ClockId::MonotonicRaw)
36 }
37 libc::CLOCK_THREAD_CPUTIME_ID => {
38 rustix::time::DynamicClockId::Known(rustix::time::ClockId::ThreadCPUTime)
39 }
40 _ => panic!("unimplemented clock_gettime({})", id),
41 };
42
43 let rustix_time = match convert_res(rustix::time::clock_gettime_dynamic(id)) {
44 Some(rustix_time) => rustix_time,
45 None => return -1,
46 };
47
48 match rustix_timespec_to_libc_timespec(rustix_time) {
49 Ok(t) => {
50 *tp = t;
51 0
52 }
53 Err(_) => {
54 set_errno(Errno(libc::EOVERFLOW));
55 -1
56 }
57 }
58}
59
60#[no_mangle]
61unsafe extern "C" fn clock_getres(id: c_int, tp: *mut libc::timespec) -> c_int {
62 libc!(libc::clock_getres(id, tp));
63
64 let id = match id {
65 libc::CLOCK_MONOTONIC => rustix::time::ClockId::Monotonic,
66 libc::CLOCK_REALTIME => rustix::time::ClockId::Realtime,
67 _ => panic!("unimplemented clock_getres({})", id),
68 };
69
70 let rustix_time = rustix::time::clock_getres(id);
71
72 match rustix_timespec_to_libc_timespec(rustix_time) {
73 Ok(t) => {
74 *tp = t;
75 0
76 }
77 Err(_) => {
78 set_errno(Errno(libc::EOVERFLOW));
79 -1
80 }
81 }
82}
83
84#[no_mangle]
85unsafe extern "C" fn time(t: *mut libc::time_t) -> libc::time_t {
86 libc!(libc::time(t));
87
88 let mut ts: libc::timespec = { core::mem::zeroed() };
89 if clock_gettime(libc::CLOCK_REALTIME, &mut ts) == -1 {
90 return -1;
91 }
92
93 if !t.is_null() {
94 *t = ts.tv_sec;
95 }
96
97 ts.tv_sec
98}
99
100#[cfg(not(target_env = "musl"))]
101#[no_mangle]
102unsafe extern "C" fn gettimeofday(t: *mut libc::timeval, _tz: *mut libc::timezone) -> c_int {
103 libc!(libc::gettimeofday(t, _tz));
104 _gettimeofday(t)
105}
106
107#[cfg(target_env = "musl")]
108#[no_mangle]
109unsafe extern "C" fn gettimeofday(t: *mut libc::timeval, _tz: *mut libc::c_void) -> c_int {
110 libc!(libc::gettimeofday(t, _tz));
111 _gettimeofday(t)
112}
113
114unsafe fn _gettimeofday(t: *mut libc::timeval) -> c_int {
115 if t.is_null() {
116 return 0;
117 }
118
119 let mut ts: libc::timespec = { core::mem::zeroed() };
120 if clock_gettime(libc::CLOCK_REALTIME, &mut ts) == -1 {
121 return -1;
122 }
123
124 if !t.is_null() {
125 (*t).tv_sec = ts.tv_sec;
126 (*t).tv_usec = ts.tv_nsec / 1000;
127 }
128
129 0
130}
131
132#[no_mangle]
133unsafe extern "C" fn nanosleep(req: *const libc::timespec, rem: *mut libc::timespec) -> c_int {
134 libc!(libc::nanosleep(req, rem));
135
136 let req = rustix::time::Timespec {
137 tv_sec: (*req).tv_sec.into(),
138 tv_nsec: (*req).tv_nsec as _,
139 };
140 match rustix::thread::nanosleep(&req) {
141 rustix::thread::NanosleepRelativeResult::Ok => 0,
142 rustix::thread::NanosleepRelativeResult::Interrupted(remaining) => {
143 if !rem.is_null() {
144 *rem = libc::timespec {
145 tv_sec: remaining.tv_sec.try_into().unwrap(),
146 tv_nsec: remaining.tv_nsec as _,
147 };
148 }
149 set_errno(Errno(libc::EINTR));
150 -1
151 }
152 rustix::thread::NanosleepRelativeResult::Err(err) => {
153 set_errno(Errno(err.raw_os_error()));
154 -1
155 }
156 }
157}
158
159#[no_mangle]
160unsafe extern "C" fn clock_nanosleep(
161 clockid: libc::clockid_t,
162 flags: c_int,
163 req: *const libc::timespec,
164 rem: *mut libc::timespec,
165) -> c_int {
166 libc!(libc::clock_nanosleep(clockid, flags, req, rem));
167
168 let clockid = match clockid {
169 libc::CLOCK_MONOTONIC => rustix::thread::ClockId::Monotonic,
170 libc::CLOCK_REALTIME => rustix::thread::ClockId::Realtime,
171 libc::CLOCK_PROCESS_CPUTIME_ID => rustix::thread::ClockId::ProcessCPUTime,
172 libc::CLOCK_THREAD_CPUTIME_ID => rustix::thread::ClockId::ThreadCPUTime,
173 libc::CLOCK_REALTIME_COARSE => rustix::thread::ClockId::RealtimeCoarse,
174 libc::CLOCK_MONOTONIC_COARSE => rustix::thread::ClockId::MonotonicCoarse,
175 libc::CLOCK_MONOTONIC_RAW => rustix::thread::ClockId::MonotonicRaw,
176 _ => return libc::EINVAL,
177 };
178
179 let req = rustix::time::Timespec {
180 tv_sec: (*req).tv_sec.into(),
181 tv_nsec: (*req).tv_nsec as _,
182 };
183 if flags == libc::TIMER_ABSTIME {
184 match convert_res(rustix::thread::clock_nanosleep_absolute(clockid, &req)) {
185 Some(()) => 0,
186 None => -1,
187 }
188 } else if flags == 0 {
189 match rustix::thread::clock_nanosleep_relative(clockid, &req) {
190 rustix::thread::NanosleepRelativeResult::Ok => 0,
191 rustix::thread::NanosleepRelativeResult::Interrupted(remaining) => {
192 if !rem.is_null() {
193 *rem = libc::timespec {
194 tv_sec: remaining.tv_sec.try_into().unwrap(),
195 tv_nsec: remaining.tv_nsec as _,
196 };
197 }
198 libc::EINTR
199 }
200 rustix::thread::NanosleepRelativeResult::Err(err) => err.raw_os_error(),
201 }
202 } else {
203 libc::EINVAL
204 }
205}
206
207#[no_mangle]
208unsafe extern "C" fn sleep(seconds: c_uint) -> c_uint {
209 libc!(libc::sleep(seconds));
210
211 let req = rustix::time::Timespec {
212 tv_sec: seconds.into(),
213 tv_nsec: 0,
214 };
215 match rustix::thread::nanosleep(&req) {
216 rustix::thread::NanosleepRelativeResult::Ok => 0,
217 rustix::thread::NanosleepRelativeResult::Interrupted(remaining) => remaining.tv_sec as _,
218 rustix::thread::NanosleepRelativeResult::Err(_err) => unreachable!(),
219 }
220}
221
222#[no_mangle]
223unsafe extern "C" fn usleep(usec: libc::useconds_t) -> c_int {
224 libc!(libc::usleep(usec));
225
226 let usec: i64 = usec.into();
227 let req = rustix::time::Timespec {
228 tv_sec: usec / 1000000,
229 tv_nsec: (usec % 1000000) * 1000,
230 };
231 match rustix::thread::nanosleep(&req) {
232 rustix::thread::NanosleepRelativeResult::Ok => 0,
233 rustix::thread::NanosleepRelativeResult::Interrupted(_remaining) => {
234 set_errno(Errno(libc::EINTR));
235 -1
236 }
237 rustix::thread::NanosleepRelativeResult::Err(err) => {
238 set_errno(Errno(err.raw_os_error()));
239 -1
240 }
241 }
242}
243
244#[no_mangle]
245unsafe extern "C" fn clock_settime(id: c_int, tp: *mut libc::timespec) -> c_int {
246 libc!(libc::clock_settime(id, tp));
247
248 let id = match id {
249 libc::CLOCK_MONOTONIC => rustix::time::ClockId::Monotonic,
250 libc::CLOCK_REALTIME => rustix::time::ClockId::Realtime,
251 _ => panic!("unimplemented clock({})", id),
252 };
253
254 let timespec = rustix::time::Timespec {
255 tv_sec: (*tp).tv_sec.into(),
256 tv_nsec: (*tp).tv_nsec as _,
257 };
258
259 match convert_res(rustix::time::clock_settime(id, timespec)) {
260 Some(()) => 0,
261 None => -1,
262 }
263}
264
265#[no_mangle]
266unsafe extern "C" fn difftime(time1: libc::time_t, time0: libc::time_t) -> f64 {
267 libc!(libc::difftime(time1, time0));
268
269 (time1 as i128 - time0 as i128) as f64
270}
271
272#[no_mangle]
273unsafe extern "C" fn clock() -> libc::clock_t {
274 let time = rustix::time::clock_gettime(rustix::time::ClockId::ProcessCPUTime);
277
278 time.tv_sec
279 .checked_mul(1_000_000)
280 .map(|usec| usec + time.tv_nsec / 1000)
281 .unwrap_or(-1)
282 .try_into()
283 .unwrap_or(-1)
284}