rustix/backend/libc/time/
syscalls.rs1use crate::backend::c;
4use crate::backend::conv::ret;
5#[cfg(any(
6 linux_kernel,
7 target_os = "freebsd",
8 target_os = "fuchsia",
9 target_os = "illumos",
10 target_os = "netbsd"
11))]
12#[cfg(any(all(target_env = "gnu", fix_y2038), not(fix_y2038)))]
13use crate::backend::time::types::LibcItimerspec;
14#[cfg(not(target_os = "wasi"))]
15use crate::clockid::{ClockId, DynamicClockId};
16use crate::io;
17#[cfg(not(fix_y2038))]
18use crate::timespec::as_libc_timespec_mut_ptr;
19#[cfg(not(fix_y2038))]
20#[cfg(not(any(
21 target_os = "redox",
22 target_os = "wasi",
23 all(apple, not(target_os = "macos"))
24)))]
25use crate::timespec::as_libc_timespec_ptr;
26#[cfg(all(target_env = "gnu", fix_y2038))]
27use crate::timespec::LibcTimespec;
28use crate::timespec::Timespec;
29use core::mem::MaybeUninit;
30#[cfg(any(
31 linux_kernel,
32 target_os = "freebsd",
33 target_os = "fuchsia",
34 target_os = "illumos",
35 target_os = "netbsd"
36))]
37use {
38 crate::backend::conv::{borrowed_fd, ret_owned_fd},
39 crate::fd::{BorrowedFd, OwnedFd},
40 crate::time::{Itimerspec, TimerfdClockId, TimerfdFlags, TimerfdTimerFlags},
41};
42
43#[cfg(all(target_env = "gnu", fix_y2038))]
44weak!(fn __clock_gettime64(c::clockid_t, *mut LibcTimespec) -> c::c_int);
45#[cfg(all(target_env = "gnu", fix_y2038))]
46weak!(fn __clock_settime64(c::clockid_t, *const LibcTimespec) -> c::c_int);
47#[cfg(all(target_env = "gnu", fix_y2038))]
48weak!(fn __clock_getres64(c::clockid_t, *mut LibcTimespec) -> c::c_int);
49#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))]
50#[cfg(all(target_env = "gnu", fix_y2038))]
51weak!(fn __timerfd_gettime64(c::c_int, *mut LibcItimerspec) -> c::c_int);
52#[cfg(any(linux_kernel, target_os = "freebsd", target_os = "fuchsia"))]
53#[cfg(all(target_env = "gnu", fix_y2038))]
54weak!(fn __timerfd_settime64(c::c_int, c::c_int, *const LibcItimerspec, *mut LibcItimerspec) -> c::c_int);
55
56#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
57#[inline]
58#[must_use]
59pub(crate) fn clock_getres(id: ClockId) -> Timespec {
60 #[cfg(fix_y2038)]
63 {
64 #[cfg(target_env = "gnu")]
65 if let Some(libc_clock_getres) = __clock_getres64.get() {
66 let mut timespec = MaybeUninit::<LibcTimespec>::uninit();
67 unsafe {
68 ret(libc_clock_getres(id as c::clockid_t, timespec.as_mut_ptr())).unwrap();
69 return timespec.assume_init().into();
70 }
71 }
72
73 clock_getres_old(id)
74 }
75
76 #[cfg(not(fix_y2038))]
78 unsafe {
79 let mut timespec = MaybeUninit::<Timespec>::uninit();
80 let _ = c::clock_getres(id as c::clockid_t, as_libc_timespec_mut_ptr(&mut timespec));
81 timespec.assume_init()
82 }
83}
84
85#[cfg(fix_y2038)]
86#[must_use]
87fn clock_getres_old(id: ClockId) -> Timespec {
88 let mut old_timespec = MaybeUninit::<c::timespec>::uninit();
89
90 let old_timespec = unsafe {
91 ret(c::clock_getres(
92 id as c::clockid_t,
93 old_timespec.as_mut_ptr(),
94 ))
95 .unwrap();
96 old_timespec.assume_init()
97 };
98
99 Timespec {
100 tv_sec: old_timespec.tv_sec.into(),
101 tv_nsec: old_timespec.tv_nsec.into(),
102 }
103}
104
105#[cfg(not(target_os = "wasi"))]
106#[inline]
107#[must_use]
108pub(crate) fn clock_gettime(id: ClockId) -> Timespec {
109 #[cfg(fix_y2038)]
112 {
113 #[cfg(target_env = "gnu")]
114 if let Some(libc_clock_gettime) = __clock_gettime64.get() {
115 let mut timespec = MaybeUninit::<LibcTimespec>::uninit();
116 unsafe {
117 ret(libc_clock_gettime(
118 id as c::clockid_t,
119 timespec.as_mut_ptr(),
120 ))
121 .unwrap();
122 return timespec.assume_init().into();
123 }
124 }
125
126 clock_gettime_old(id)
127 }
128
129 #[cfg(not(fix_y2038))]
134 unsafe {
135 let mut timespec = MaybeUninit::<Timespec>::uninit();
136 ret(c::clock_gettime(
137 id as c::clockid_t,
138 as_libc_timespec_mut_ptr(&mut timespec),
139 ))
140 .unwrap();
141 let timespec = timespec.assume_init();
142 #[cfg(apple)]
143 let timespec = fix_negative_timespec_nsecs(timespec);
144 timespec
145 }
146}
147
148#[cfg(fix_y2038)]
149#[must_use]
150fn clock_gettime_old(id: ClockId) -> Timespec {
151 let mut old_timespec = MaybeUninit::<c::timespec>::uninit();
152
153 let old_timespec = unsafe {
154 ret(c::clock_gettime(
155 id as c::clockid_t,
156 old_timespec.as_mut_ptr(),
157 ))
158 .unwrap();
159 old_timespec.assume_init()
160 };
161
162 Timespec {
163 tv_sec: old_timespec.tv_sec.into(),
164 tv_nsec: old_timespec.tv_nsec.into(),
165 }
166}
167
168#[cfg(not(target_os = "wasi"))]
169#[inline]
170pub(crate) fn clock_gettime_dynamic(id: DynamicClockId<'_>) -> io::Result<Timespec> {
171 let id: c::clockid_t = match id {
172 DynamicClockId::Known(id) => id as c::clockid_t,
173
174 #[cfg(linux_kernel)]
175 DynamicClockId::Dynamic(fd) => {
176 use crate::fd::AsRawFd as _;
177 const CLOCKFD: i32 = 3;
178 (!fd.as_raw_fd() << 3) | CLOCKFD
179 }
180
181 #[cfg(not(linux_kernel))]
182 DynamicClockId::Dynamic(_fd) => {
183 return Err(io::Errno::INVAL);
185 }
186
187 #[cfg(any(linux_kernel, target_os = "fuchsia"))]
188 DynamicClockId::RealtimeAlarm => c::CLOCK_REALTIME_ALARM,
189
190 #[cfg(linux_kernel)]
191 DynamicClockId::Tai => c::CLOCK_TAI,
192
193 #[cfg(any(
194 linux_kernel,
195 target_os = "freebsd",
196 target_os = "fuchsia",
197 target_os = "openbsd"
198 ))]
199 DynamicClockId::Boottime => c::CLOCK_BOOTTIME,
200
201 #[cfg(any(linux_kernel, target_os = "fuchsia"))]
202 DynamicClockId::BoottimeAlarm => c::CLOCK_BOOTTIME_ALARM,
203 };
204
205 #[cfg(fix_y2038)]
208 {
209 #[cfg(target_env = "gnu")]
210 if let Some(libc_clock_gettime) = __clock_gettime64.get() {
211 let mut timespec = MaybeUninit::<LibcTimespec>::uninit();
212 unsafe {
213 ret(libc_clock_gettime(
214 id as c::clockid_t,
215 timespec.as_mut_ptr(),
216 ))?;
217
218 return Ok(timespec.assume_init().into());
219 }
220 }
221
222 clock_gettime_dynamic_old(id)
223 }
224
225 #[cfg(not(fix_y2038))]
227 unsafe {
228 let mut timespec = MaybeUninit::<Timespec>::uninit();
229
230 ret(c::clock_gettime(
231 id as c::clockid_t,
232 as_libc_timespec_mut_ptr(&mut timespec),
233 ))?;
234 let timespec = timespec.assume_init();
235 #[cfg(apple)]
236 let timespec = fix_negative_timespec_nsecs(timespec);
237 Ok(timespec)
238 }
239}
240
241#[cfg(fix_y2038)]
242#[inline]
243fn clock_gettime_dynamic_old(id: c::clockid_t) -> io::Result<Timespec> {
244 let mut old_timespec = MaybeUninit::<c::timespec>::uninit();
245
246 let old_timespec = unsafe {
247 ret(c::clock_gettime(
248 id as c::clockid_t,
249 old_timespec.as_mut_ptr(),
250 ))?;
251
252 old_timespec.assume_init()
253 };
254
255 Ok(Timespec {
256 tv_sec: old_timespec.tv_sec.into(),
257 tv_nsec: old_timespec.tv_nsec.into(),
258 })
259}
260
261#[cfg(not(any(
262 target_os = "redox",
263 target_os = "wasi",
264 all(apple, not(target_os = "macos"))
265)))]
266#[inline]
267pub(crate) fn clock_settime(id: ClockId, timespec: Timespec) -> io::Result<()> {
268 #[cfg(fix_y2038)]
271 {
272 #[cfg(target_env = "gnu")]
273 if let Some(libc_clock_settime) = __clock_settime64.get() {
274 unsafe {
275 let mut new_timespec = core::mem::zeroed::<LibcTimespec>();
276 new_timespec.tv_sec = timespec.tv_sec;
277 new_timespec.tv_nsec = timespec.tv_nsec as _;
278 return ret(libc_clock_settime(id as c::clockid_t, &new_timespec));
279 }
280 }
281
282 clock_settime_old(id, timespec)
283 }
284
285 #[cfg(not(fix_y2038))]
287 unsafe {
288 ret(c::clock_settime(
289 id as c::clockid_t,
290 as_libc_timespec_ptr(×pec),
291 ))
292 }
293}
294
295#[cfg(not(any(
296 target_os = "redox",
297 target_os = "wasi",
298 all(apple, not(target_os = "macos"))
299)))]
300#[cfg(fix_y2038)]
301fn clock_settime_old(id: ClockId, timespec: Timespec) -> io::Result<()> {
302 let old_timespec = c::timespec {
303 tv_sec: timespec
304 .tv_sec
305 .try_into()
306 .map_err(|_| io::Errno::OVERFLOW)?,
307 tv_nsec: timespec.tv_nsec as _,
308 };
309
310 unsafe { ret(c::clock_settime(id as c::clockid_t, &old_timespec)) }
311}
312
313#[cfg(any(
314 linux_kernel,
315 target_os = "freebsd",
316 target_os = "fuchsia",
317 target_os = "illumos",
318 target_os = "netbsd"
319))]
320pub(crate) fn timerfd_create(id: TimerfdClockId, flags: TimerfdFlags) -> io::Result<OwnedFd> {
321 unsafe { ret_owned_fd(c::timerfd_create(id as c::clockid_t, bitflags_bits!(flags))) }
322}
323
324#[cfg(any(
325 linux_kernel,
326 target_os = "freebsd",
327 target_os = "fuchsia",
328 target_os = "illumos",
329 target_os = "netbsd"
330))]
331pub(crate) fn timerfd_settime(
332 fd: BorrowedFd<'_>,
333 flags: TimerfdTimerFlags,
334 new_value: &Itimerspec,
335) -> io::Result<Itimerspec> {
336 #[cfg(fix_y2038)]
339 {
340 #[cfg(target_env = "gnu")]
341 if let Some(libc_timerfd_settime) = __timerfd_settime64.get() {
342 let mut result = MaybeUninit::<LibcItimerspec>::uninit();
343 unsafe {
344 ret(libc_timerfd_settime(
345 borrowed_fd(fd),
346 bitflags_bits!(flags),
347 &new_value.clone().into(),
348 result.as_mut_ptr(),
349 ))?;
350 return Ok(result.assume_init().into());
351 }
352 }
353
354 timerfd_settime_old(fd, flags, new_value)
355 }
356
357 #[cfg(not(fix_y2038))]
358 unsafe {
359 use crate::backend::time::types::{as_libc_itimerspec_mut_ptr, as_libc_itimerspec_ptr};
360
361 let mut result = MaybeUninit::<LibcItimerspec>::uninit();
362 ret(c::timerfd_settime(
363 borrowed_fd(fd),
364 bitflags_bits!(flags),
365 as_libc_itimerspec_ptr(new_value),
366 as_libc_itimerspec_mut_ptr(&mut result),
367 ))?;
368 Ok(result.assume_init())
369 }
370}
371
372#[cfg(any(
373 linux_kernel,
374 target_os = "freebsd",
375 target_os = "fuchsia",
376 target_os = "illumos",
377 target_os = "netbsd"
378))]
379#[cfg(fix_y2038)]
380fn timerfd_settime_old(
381 fd: BorrowedFd<'_>,
382 flags: TimerfdTimerFlags,
383 new_value: &Itimerspec,
384) -> io::Result<Itimerspec> {
385 let mut old_result = MaybeUninit::<c::itimerspec>::uninit();
386
387 let old_new_value = c::itimerspec {
389 it_interval: c::timespec {
390 tv_sec: new_value
391 .it_interval
392 .tv_sec
393 .try_into()
394 .map_err(|_| io::Errno::OVERFLOW)?,
395 tv_nsec: new_value
396 .it_interval
397 .tv_nsec
398 .try_into()
399 .map_err(|_| io::Errno::INVAL)?,
400 },
401 it_value: c::timespec {
402 tv_sec: new_value
403 .it_value
404 .tv_sec
405 .try_into()
406 .map_err(|_| io::Errno::OVERFLOW)?,
407 tv_nsec: new_value
408 .it_value
409 .tv_nsec
410 .try_into()
411 .map_err(|_| io::Errno::INVAL)?,
412 },
413 };
414
415 let old_result = unsafe {
416 ret(c::timerfd_settime(
417 borrowed_fd(fd),
418 bitflags_bits!(flags),
419 &old_new_value,
420 old_result.as_mut_ptr(),
421 ))?;
422 old_result.assume_init()
423 };
424
425 Ok(Itimerspec {
426 it_interval: Timespec {
427 tv_sec: old_result
428 .it_interval
429 .tv_sec
430 .try_into()
431 .map_err(|_| io::Errno::OVERFLOW)?,
432 tv_nsec: old_result.it_interval.tv_nsec as _,
433 },
434 it_value: Timespec {
435 tv_sec: old_result
436 .it_interval
437 .tv_sec
438 .try_into()
439 .map_err(|_| io::Errno::OVERFLOW)?,
440 tv_nsec: old_result.it_interval.tv_nsec as _,
441 },
442 })
443}
444
445#[cfg(any(
446 linux_kernel,
447 target_os = "freebsd",
448 target_os = "fuchsia",
449 target_os = "illumos",
450 target_os = "netbsd"
451))]
452pub(crate) fn timerfd_gettime(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> {
453 #[cfg(fix_y2038)]
456 {
457 #[cfg(target_env = "gnu")]
458 if let Some(libc_timerfd_gettime) = __timerfd_gettime64.get() {
459 let mut result = MaybeUninit::<LibcItimerspec>::uninit();
460 unsafe {
461 ret(libc_timerfd_gettime(borrowed_fd(fd), result.as_mut_ptr()))?;
462 return Ok(result.assume_init().into());
463 }
464 }
465
466 timerfd_gettime_old(fd)
467 }
468
469 #[cfg(not(fix_y2038))]
470 unsafe {
471 use crate::backend::time::types::as_libc_itimerspec_mut_ptr;
472
473 let mut result = MaybeUninit::<LibcItimerspec>::uninit();
474 ret(c::timerfd_gettime(
475 borrowed_fd(fd),
476 as_libc_itimerspec_mut_ptr(&mut result),
477 ))?;
478 Ok(result.assume_init())
479 }
480}
481
482#[cfg(any(
483 linux_kernel,
484 target_os = "freebsd",
485 target_os = "fuchsia",
486 target_os = "illumos",
487 target_os = "netbsd"
488))]
489#[cfg(fix_y2038)]
490fn timerfd_gettime_old(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> {
491 let mut old_result = MaybeUninit::<c::itimerspec>::uninit();
492
493 let old_result = unsafe {
494 ret(c::timerfd_gettime(borrowed_fd(fd), old_result.as_mut_ptr()))?;
495 old_result.assume_init()
496 };
497
498 Ok(Itimerspec {
499 it_interval: Timespec {
500 tv_sec: old_result
501 .it_interval
502 .tv_sec
503 .try_into()
504 .map_err(|_| io::Errno::OVERFLOW)?,
505 tv_nsec: old_result.it_interval.tv_nsec as _,
506 },
507 it_value: Timespec {
508 tv_sec: old_result
509 .it_interval
510 .tv_sec
511 .try_into()
512 .map_err(|_| io::Errno::OVERFLOW)?,
513 tv_nsec: old_result.it_interval.tv_nsec as _,
514 },
515 })
516}
517
518#[cfg(apple)]
520#[cfg(not(fix_y2038))]
521fn fix_negative_timespec_nsecs(mut ts: Timespec) -> Timespec {
522 let (sec, nsec) = crate::timespec::fix_negative_nsecs(ts.tv_sec as _, ts.tv_nsec as _);
523 ts.tv_sec = sec as _;
524 ts.tv_nsec = nsec as _;
525 ts
526}