rustix/backend/linux_raw/time/
syscalls.rs
1#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
7
8use crate::backend::conv::{by_ref, ret, ret_infallible, ret_owned_fd};
9use crate::clockid::ClockId;
10use crate::fd::{BorrowedFd, OwnedFd};
11use crate::io;
12use crate::time::{Itimerspec, TimerfdClockId, TimerfdFlags, TimerfdTimerFlags};
13use crate::timespec::Timespec;
14use core::mem::MaybeUninit;
15#[cfg(target_pointer_width = "32")]
16use linux_raw_sys::general::itimerspec as __kernel_old_itimerspec;
17#[cfg(target_pointer_width = "32")]
18use linux_raw_sys::general::timespec as __kernel_old_timespec;
19
20pub(crate) use crate::backend::vdso_wrappers::{clock_gettime, clock_gettime_dynamic};
22
23#[inline]
24#[must_use]
25pub(crate) fn clock_getres(id: ClockId) -> Timespec {
26 #[cfg(target_pointer_width = "32")]
27 unsafe {
28 let mut result = MaybeUninit::<Timespec>::uninit();
29 if let Err(err) = ret(syscall!(__NR_clock_getres_time64, id, &mut result)) {
30 debug_assert_eq!(err, io::Errno::NOSYS);
32 clock_getres_old(id, &mut result);
33 }
34 result.assume_init()
35 }
36 #[cfg(target_pointer_width = "64")]
37 unsafe {
38 let mut result = MaybeUninit::<Timespec>::uninit();
39 ret_infallible(syscall!(__NR_clock_getres, id, &mut result));
40 result.assume_init()
41 }
42}
43
44#[cfg(target_pointer_width = "32")]
45unsafe fn clock_getres_old(id: ClockId, result: &mut MaybeUninit<Timespec>) {
46 let mut old_result = MaybeUninit::<__kernel_old_timespec>::uninit();
47 ret_infallible(syscall!(__NR_clock_getres, id, &mut old_result));
48 let old_result = old_result.assume_init();
49 result.write(Timespec {
50 tv_sec: old_result.tv_sec.into(),
51 tv_nsec: old_result.tv_nsec.into(),
52 });
53}
54
55#[inline]
56pub(crate) fn clock_settime(id: ClockId, timespec: Timespec) -> io::Result<()> {
57 #[cfg(target_pointer_width = "32")]
60 unsafe {
61 match ret(syscall_readonly!(
62 __NR_clock_settime64,
63 id,
64 by_ref(×pec)
65 )) {
66 Err(io::Errno::NOSYS) => clock_settime_old(id, timespec),
67 otherwise => otherwise,
68 }
69 }
70 #[cfg(target_pointer_width = "64")]
71 unsafe {
72 ret(syscall_readonly!(__NR_clock_settime, id, by_ref(×pec)))
73 }
74}
75
76#[cfg(target_pointer_width = "32")]
77unsafe fn clock_settime_old(id: ClockId, timespec: Timespec) -> io::Result<()> {
78 let old_timespec = __kernel_old_timespec {
79 tv_sec: timespec
80 .tv_sec
81 .try_into()
82 .map_err(|_| io::Errno::OVERFLOW)?,
83 tv_nsec: timespec.tv_nsec as _,
84 };
85 ret(syscall_readonly!(
86 __NR_clock_settime,
87 id,
88 by_ref(&old_timespec)
89 ))
90}
91
92#[inline]
93pub(crate) fn timerfd_create(clockid: TimerfdClockId, flags: TimerfdFlags) -> io::Result<OwnedFd> {
94 unsafe { ret_owned_fd(syscall_readonly!(__NR_timerfd_create, clockid, flags)) }
95}
96
97#[inline]
98pub(crate) fn timerfd_settime(
99 fd: BorrowedFd<'_>,
100 flags: TimerfdTimerFlags,
101 new_value: &Itimerspec,
102) -> io::Result<Itimerspec> {
103 let mut result = MaybeUninit::<Itimerspec>::uninit();
104
105 #[cfg(target_pointer_width = "64")]
106 unsafe {
107 ret(syscall!(
108 __NR_timerfd_settime,
109 fd,
110 flags,
111 by_ref(new_value),
112 &mut result
113 ))?;
114 Ok(result.assume_init())
115 }
116
117 #[cfg(target_pointer_width = "32")]
118 unsafe {
119 ret(syscall!(
120 __NR_timerfd_settime64,
121 fd,
122 flags,
123 by_ref(new_value),
124 &mut result
125 ))
126 .or_else(|err| {
127 if err == io::Errno::NOSYS {
129 timerfd_settime_old(fd, flags, new_value, &mut result)
130 } else {
131 Err(err)
132 }
133 })?;
134 Ok(result.assume_init())
135 }
136}
137
138#[cfg(target_pointer_width = "32")]
139unsafe fn timerfd_settime_old(
140 fd: BorrowedFd<'_>,
141 flags: TimerfdTimerFlags,
142 new_value: &Itimerspec,
143 result: &mut MaybeUninit<Itimerspec>,
144) -> io::Result<()> {
145 let mut old_result = MaybeUninit::<__kernel_old_itimerspec>::uninit();
146
147 let old_new_value = __kernel_old_itimerspec {
149 it_interval: __kernel_old_timespec {
150 tv_sec: new_value
151 .it_interval
152 .tv_sec
153 .try_into()
154 .map_err(|_| io::Errno::OVERFLOW)?,
155 tv_nsec: new_value
156 .it_interval
157 .tv_nsec
158 .try_into()
159 .map_err(|_| io::Errno::INVAL)?,
160 },
161 it_value: __kernel_old_timespec {
162 tv_sec: new_value
163 .it_value
164 .tv_sec
165 .try_into()
166 .map_err(|_| io::Errno::OVERFLOW)?,
167 tv_nsec: new_value
168 .it_value
169 .tv_nsec
170 .try_into()
171 .map_err(|_| io::Errno::INVAL)?,
172 },
173 };
174 ret(syscall!(
175 __NR_timerfd_settime,
176 fd,
177 flags,
178 by_ref(&old_new_value),
179 &mut old_result
180 ))?;
181 let old_result = old_result.assume_init();
182 result.write(Itimerspec {
183 it_interval: Timespec {
184 tv_sec: old_result.it_interval.tv_sec.into(),
185 tv_nsec: old_result.it_interval.tv_nsec.into(),
186 },
187 it_value: Timespec {
188 tv_sec: old_result.it_value.tv_sec.into(),
189 tv_nsec: old_result.it_value.tv_nsec.into(),
190 },
191 });
192 Ok(())
193}
194
195#[inline]
196pub(crate) fn timerfd_gettime(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> {
197 let mut result = MaybeUninit::<Itimerspec>::uninit();
198
199 #[cfg(target_pointer_width = "64")]
200 unsafe {
201 ret(syscall!(__NR_timerfd_gettime, fd, &mut result))?;
202 Ok(result.assume_init())
203 }
204
205 #[cfg(target_pointer_width = "32")]
206 unsafe {
207 ret(syscall!(__NR_timerfd_gettime64, fd, &mut result)).or_else(|err| {
208 if err == io::Errno::NOSYS {
210 timerfd_gettime_old(fd, &mut result)
211 } else {
212 Err(err)
213 }
214 })?;
215 Ok(result.assume_init())
216 }
217}
218
219#[cfg(target_pointer_width = "32")]
220unsafe fn timerfd_gettime_old(
221 fd: BorrowedFd<'_>,
222 result: &mut MaybeUninit<Itimerspec>,
223) -> io::Result<()> {
224 let mut old_result = MaybeUninit::<__kernel_old_itimerspec>::uninit();
225 ret(syscall!(__NR_timerfd_gettime, fd, &mut old_result))?;
226 let old_result = old_result.assume_init();
227 result.write(Itimerspec {
228 it_interval: Timespec {
229 tv_sec: old_result.it_interval.tv_sec.into(),
230 tv_nsec: old_result.it_interval.tv_nsec.into(),
231 },
232 it_value: Timespec {
233 tv_sec: old_result.it_value.tv_sec.into(),
234 tv_nsec: old_result.it_value.tv_nsec.into(),
235 },
236 });
237 Ok(())
238}