]> git.proxmox.com Git - rustc.git/blame - vendor/rustix-0.37.6/src/backend/linux_raw/time/syscalls.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / vendor / rustix-0.37.6 / src / backend / linux_raw / time / syscalls.rs
CommitLineData
fe692bf9
FG
1//! linux_raw syscalls supporting `rustix::time`.
2//!
3//! # Safety
4//!
5//! See the `rustix::backend` module documentation for details.
6#![allow(unsafe_code)]
7#![allow(clippy::undocumented_unsafe_blocks)]
8
781aab86
FG
9#[cfg(feature = "time")]
10use super::super::conv::{by_ref, ret_owned_fd};
fe692bf9
FG
11use super::super::conv::{ret, ret_infallible};
12use super::types::ClockId;
781aab86
FG
13#[cfg(feature = "time")]
14use crate::fd::BorrowedFd;
15#[cfg(feature = "time")]
16use crate::fd::OwnedFd;
fe692bf9 17use crate::io;
781aab86
FG
18#[cfg(feature = "time")]
19use crate::time::{Itimerspec, TimerfdClockId, TimerfdFlags, TimerfdTimerFlags};
fe692bf9
FG
20use core::mem::MaybeUninit;
21use linux_raw_sys::general::__kernel_timespec;
fe692bf9 22#[cfg(feature = "time")]
781aab86 23#[cfg(target_pointer_width = "32")]
fe692bf9 24use {core::convert::TryInto, linux_raw_sys::general::itimerspec as __kernel_old_itimerspec};
781aab86
FG
25#[cfg(target_pointer_width = "32")]
26use {core::ptr, linux_raw_sys::general::timespec as __kernel_old_timespec};
fe692bf9
FG
27
28// `clock_gettime` has special optimizations via the vDSO.
29#[cfg(feature = "time")]
30pub(crate) use super::super::vdso_wrappers::{clock_gettime, clock_gettime_dynamic};
31
32#[inline]
33pub(crate) fn clock_getres(which_clock: ClockId) -> __kernel_timespec {
34 #[cfg(target_pointer_width = "32")]
35 unsafe {
36 let mut result = MaybeUninit::<__kernel_timespec>::uninit();
37 if let Err(err) = ret(syscall!(__NR_clock_getres_time64, which_clock, &mut result)) {
38 // See the comments in `rustix_clock_gettime_via_syscall` about
39 // emulation.
40 debug_assert_eq!(err, io::Errno::NOSYS);
41 clock_getres_old(which_clock, &mut result);
42 }
43 result.assume_init()
44 }
45 #[cfg(target_pointer_width = "64")]
46 unsafe {
47 let mut result = MaybeUninit::<__kernel_timespec>::uninit();
48 ret_infallible(syscall!(__NR_clock_getres, which_clock, &mut result));
49 result.assume_init()
50 }
51}
52
53#[cfg(target_pointer_width = "32")]
54unsafe fn clock_getres_old(which_clock: ClockId, result: &mut MaybeUninit<__kernel_timespec>) {
55 let mut old_result = MaybeUninit::<__kernel_old_timespec>::uninit();
56 ret_infallible(syscall!(__NR_clock_getres, which_clock, &mut old_result));
57 let old_result = old_result.assume_init();
58 // TODO: With Rust 1.55, we can use MaybeUninit::write here.
781aab86
FG
59 ptr::write(
60 result.as_mut_ptr(),
61 __kernel_timespec {
62 tv_sec: old_result.tv_sec.into(),
63 tv_nsec: old_result.tv_nsec.into(),
64 },
65 );
fe692bf9
FG
66}
67
68#[cfg(feature = "time")]
69#[inline]
70pub(crate) fn clock_settime(which_clock: ClockId, timespec: __kernel_timespec) -> io::Result<()> {
fe692bf9
FG
71 #[cfg(target_pointer_width = "32")]
72 unsafe {
73 match ret(syscall_readonly!(
74 __NR_clock_settime64,
75 which_clock,
76 by_ref(&timespec)
77 )) {
78 Err(io::Errno::NOSYS) => clock_settime_old(which_clock, timespec),
79 otherwise => otherwise,
80 }
81 }
82 #[cfg(target_pointer_width = "64")]
83 unsafe {
84 ret(syscall_readonly!(
85 __NR_clock_settime,
86 which_clock,
87 by_ref(&timespec)
88 ))
89 }
90}
91
92#[cfg(feature = "time")]
93#[cfg(target_pointer_width = "32")]
94unsafe fn clock_settime_old(which_clock: ClockId, timespec: __kernel_timespec) -> io::Result<()> {
95 let old_timespec = __kernel_old_timespec {
96 tv_sec: timespec
97 .tv_sec
98 .try_into()
99 .map_err(|_| io::Errno::OVERFLOW)?,
100 tv_nsec: timespec.tv_nsec as _,
101 };
102 ret(syscall_readonly!(
103 __NR_clock_settime,
104 which_clock,
105 by_ref(&old_timespec)
106 ))
107}
108
109#[cfg(feature = "time")]
110#[inline]
111pub(crate) fn timerfd_create(clockid: TimerfdClockId, flags: TimerfdFlags) -> io::Result<OwnedFd> {
112 unsafe { ret_owned_fd(syscall!(__NR_timerfd_create, clockid, flags)) }
113}
114
115#[cfg(feature = "time")]
116#[inline]
117pub(crate) fn timerfd_settime(
118 fd: BorrowedFd<'_>,
119 flags: TimerfdTimerFlags,
120 new_value: &Itimerspec,
121) -> io::Result<Itimerspec> {
122 let mut result = MaybeUninit::<Itimerspec>::uninit();
123
124 #[cfg(target_pointer_width = "64")]
125 unsafe {
126 ret(syscall!(
127 __NR_timerfd_settime,
128 fd,
129 flags,
130 by_ref(new_value),
131 &mut result
132 ))?;
133 Ok(result.assume_init())
134 }
135
136 #[cfg(target_pointer_width = "32")]
137 unsafe {
138 ret(syscall!(
139 __NR_timerfd_settime64,
140 fd,
141 flags,
142 by_ref(new_value),
143 &mut result
144 ))
145 .or_else(|err| {
146 // See the comments in `rustix_clock_gettime_via_syscall` about
147 // emulation.
148 if err == io::Errno::NOSYS {
149 timerfd_settime_old(fd, flags, new_value, &mut result)
150 } else {
151 Err(err)
152 }
153 })?;
154 Ok(result.assume_init())
155 }
156}
157
158#[cfg(feature = "time")]
159#[cfg(target_pointer_width = "32")]
160unsafe fn timerfd_settime_old(
161 fd: BorrowedFd<'_>,
162 flags: TimerfdTimerFlags,
163 new_value: &Itimerspec,
164 result: &mut MaybeUninit<Itimerspec>,
165) -> io::Result<()> {
166 let mut old_result = MaybeUninit::<__kernel_old_itimerspec>::uninit();
167
168 // Convert `new_value` to the old `__kernel_old_itimerspec` format.
169 let old_new_value = __kernel_old_itimerspec {
170 it_interval: __kernel_old_timespec {
171 tv_sec: new_value
172 .it_interval
173 .tv_sec
174 .try_into()
175 .map_err(|_| io::Errno::OVERFLOW)?,
176 tv_nsec: new_value
177 .it_interval
178 .tv_nsec
179 .try_into()
180 .map_err(|_| io::Errno::INVAL)?,
181 },
182 it_value: __kernel_old_timespec {
183 tv_sec: new_value
184 .it_value
185 .tv_sec
186 .try_into()
187 .map_err(|_| io::Errno::OVERFLOW)?,
188 tv_nsec: new_value
189 .it_value
190 .tv_nsec
191 .try_into()
192 .map_err(|_| io::Errno::INVAL)?,
193 },
194 };
195 ret(syscall!(
196 __NR_timerfd_settime,
197 fd,
198 flags,
199 by_ref(&old_new_value),
200 &mut old_result
201 ))?;
202 let old_result = old_result.assume_init();
203 // TODO: With Rust 1.55, we can use MaybeUninit::write here.
781aab86
FG
204 ptr::write(
205 result.as_mut_ptr(),
206 Itimerspec {
207 it_interval: __kernel_timespec {
208 tv_sec: old_result.it_interval.tv_sec.into(),
209 tv_nsec: old_result.it_interval.tv_nsec.into(),
210 },
211 it_value: __kernel_timespec {
212 tv_sec: old_result.it_value.tv_sec.into(),
213 tv_nsec: old_result.it_value.tv_nsec.into(),
214 },
fe692bf9 215 },
781aab86 216 );
fe692bf9
FG
217 Ok(())
218}
219
220#[cfg(feature = "time")]
221#[inline]
222pub(crate) fn timerfd_gettime(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> {
223 let mut result = MaybeUninit::<Itimerspec>::uninit();
224
225 #[cfg(target_pointer_width = "64")]
226 unsafe {
227 ret(syscall!(__NR_timerfd_gettime, fd, &mut result))?;
228 Ok(result.assume_init())
229 }
230
231 #[cfg(target_pointer_width = "32")]
232 unsafe {
233 ret(syscall!(__NR_timerfd_gettime64, fd, &mut result)).or_else(|err| {
234 // See the comments in `rustix_clock_gettime_via_syscall` about
235 // emulation.
236 if err == io::Errno::NOSYS {
237 timerfd_gettime_old(fd, &mut result)
238 } else {
239 Err(err)
240 }
241 })?;
242 Ok(result.assume_init())
243 }
244}
245
246#[cfg(feature = "time")]
247#[cfg(target_pointer_width = "32")]
248unsafe fn timerfd_gettime_old(
249 fd: BorrowedFd<'_>,
250 result: &mut MaybeUninit<Itimerspec>,
251) -> io::Result<()> {
252 let mut old_result = MaybeUninit::<__kernel_old_itimerspec>::uninit();
253 ret(syscall!(__NR_timerfd_gettime, fd, &mut old_result))?;
254 let old_result = old_result.assume_init();
255 // TODO: With Rust 1.55, we can use MaybeUninit::write here.
781aab86
FG
256 ptr::write(
257 result.as_mut_ptr(),
258 Itimerspec {
259 it_interval: __kernel_timespec {
260 tv_sec: old_result.it_interval.tv_sec.into(),
261 tv_nsec: old_result.it_interval.tv_nsec.into(),
262 },
263 it_value: __kernel_timespec {
264 tv_sec: old_result.it_value.tv_sec.into(),
265 tv_nsec: old_result.it_value.tv_nsec.into(),
266 },
fe692bf9 267 },
781aab86 268 );
fe692bf9
FG
269 Ok(())
270}