]> git.proxmox.com Git - rustc.git/blame - vendor/rustix-0.36.5/src/backend/linux_raw/thread/syscalls.rs
Merge 1.70 into proxmox/bookworm
[rustc.git] / vendor / rustix-0.36.5 / src / backend / linux_raw / thread / syscalls.rs
CommitLineData
353b0b11
FG
1//! linux_raw syscalls supporting `rustix::thread`.
2//!
3//! # Safety
4//!
5//! See the `rustix::backend` module documentation for details.
6#![allow(unsafe_code)]
7#![allow(clippy::undocumented_unsafe_blocks)]
8
9use super::super::c;
10use super::super::conv::{
11 by_ref, c_int, c_uint, ret, ret_c_int, ret_usize, ret_usize_infallible, zero,
12};
13use crate::fd::BorrowedFd;
14use crate::io;
15use crate::process::{Pid, RawNonZeroPid};
16use crate::thread::{ClockId, FutexFlags, FutexOperation, NanosleepRelativeResult, Timespec};
17use core::mem::MaybeUninit;
18use linux_raw_sys::general::{__kernel_pid_t, __kernel_timespec, TIMER_ABSTIME};
19#[cfg(target_pointer_width = "32")]
20use {
21 core::convert::TryInto, core::ptr, linux_raw_sys::general::timespec as __kernel_old_timespec,
22};
23
24#[inline]
25pub(crate) fn clock_nanosleep_relative(
26 id: ClockId,
27 req: &__kernel_timespec,
28) -> NanosleepRelativeResult {
29 #[cfg(target_pointer_width = "32")]
30 unsafe {
31 let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
32 match ret(syscall!(
33 __NR_clock_nanosleep_time64,
34 id,
35 c_int(0),
36 by_ref(req),
37 &mut rem
38 ))
39 .or_else(|err| {
40 // See the comments in `rustix_clock_gettime_via_syscall` about
41 // emulation.
42 if err == io::Errno::NOSYS {
43 clock_nanosleep_relative_old(id, req, &mut rem)
44 } else {
45 Err(err)
46 }
47 }) {
48 Ok(()) => NanosleepRelativeResult::Ok,
49 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
50 Err(err) => NanosleepRelativeResult::Err(err),
51 }
52 }
53 #[cfg(target_pointer_width = "64")]
54 unsafe {
55 let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
56 match ret(syscall!(
57 __NR_clock_nanosleep,
58 id,
59 c_int(0),
60 by_ref(req),
61 &mut rem
62 )) {
63 Ok(()) => NanosleepRelativeResult::Ok,
64 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
65 Err(err) => NanosleepRelativeResult::Err(err),
66 }
67 }
68}
69
70#[cfg(target_pointer_width = "32")]
71unsafe fn clock_nanosleep_relative_old(
72 id: ClockId,
73 req: &__kernel_timespec,
74 rem: &mut MaybeUninit<__kernel_timespec>,
75) -> io::Result<()> {
76 let old_req = __kernel_old_timespec {
77 tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
78 tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
79 };
80 let mut old_rem = MaybeUninit::<__kernel_old_timespec>::uninit();
81 ret(syscall!(
82 __NR_clock_nanosleep,
83 id,
84 c_int(0),
85 by_ref(&old_req),
86 &mut old_rem
87 ))?;
88 let old_rem = old_rem.assume_init();
89 // TODO: With Rust 1.55, we can use MaybeUninit::write here.
90 ptr::write(
91 rem.as_mut_ptr(),
92 __kernel_timespec {
93 tv_sec: old_rem.tv_sec.into(),
94 tv_nsec: old_rem.tv_nsec.into(),
95 },
96 );
97 Ok(())
98}
99
100#[inline]
101pub(crate) fn clock_nanosleep_absolute(id: ClockId, req: &__kernel_timespec) -> io::Result<()> {
102 #[cfg(target_pointer_width = "32")]
103 unsafe {
104 ret(syscall_readonly!(
105 __NR_clock_nanosleep_time64,
106 id,
107 c_uint(TIMER_ABSTIME),
108 by_ref(req),
109 zero()
110 ))
111 .or_else(|err| {
112 // See the comments in `rustix_clock_gettime_via_syscall` about
113 // emulation.
114 if err == io::Errno::NOSYS {
115 clock_nanosleep_absolute_old(id, req)
116 } else {
117 Err(err)
118 }
119 })
120 }
121 #[cfg(target_pointer_width = "64")]
122 unsafe {
123 ret(syscall_readonly!(
124 __NR_clock_nanosleep,
125 id,
126 c_uint(TIMER_ABSTIME),
127 by_ref(req),
128 zero()
129 ))
130 }
131}
132
133#[cfg(target_pointer_width = "32")]
134unsafe fn clock_nanosleep_absolute_old(id: ClockId, req: &__kernel_timespec) -> io::Result<()> {
135 let old_req = __kernel_old_timespec {
136 tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
137 tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
138 };
139 ret(syscall_readonly!(
140 __NR_clock_nanosleep,
141 id,
142 c_int(0),
143 by_ref(&old_req),
144 zero()
145 ))
146}
147
148#[inline]
149pub(crate) fn nanosleep(req: &__kernel_timespec) -> NanosleepRelativeResult {
150 #[cfg(target_pointer_width = "32")]
151 unsafe {
152 let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
153 match ret(syscall!(
154 __NR_clock_nanosleep_time64,
155 ClockId::Realtime,
156 c_int(0),
157 by_ref(req),
158 &mut rem
159 ))
160 .or_else(|err| {
161 // See the comments in `rustix_clock_gettime_via_syscall` about
162 // emulation.
163 if err == io::Errno::NOSYS {
164 nanosleep_old(req, &mut rem)
165 } else {
166 Err(err)
167 }
168 }) {
169 Ok(()) => NanosleepRelativeResult::Ok,
170 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
171 Err(err) => NanosleepRelativeResult::Err(err),
172 }
173 }
174 #[cfg(target_pointer_width = "64")]
175 unsafe {
176 let mut rem = MaybeUninit::<__kernel_timespec>::uninit();
177 match ret(syscall!(__NR_nanosleep, by_ref(req), &mut rem)) {
178 Ok(()) => NanosleepRelativeResult::Ok,
179 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(rem.assume_init()),
180 Err(err) => NanosleepRelativeResult::Err(err),
181 }
182 }
183}
184
185#[cfg(target_pointer_width = "32")]
186unsafe fn nanosleep_old(
187 req: &__kernel_timespec,
188 rem: &mut MaybeUninit<__kernel_timespec>,
189) -> io::Result<()> {
190 let old_req = __kernel_old_timespec {
191 tv_sec: req.tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
192 tv_nsec: req.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
193 };
194 let mut old_rem = MaybeUninit::<__kernel_old_timespec>::uninit();
195 ret(syscall!(__NR_nanosleep, by_ref(&old_req), &mut old_rem))?;
196 let old_rem = old_rem.assume_init();
197 // TODO: With Rust 1.55, we can use MaybeUninit::write here.
198 ptr::write(
199 rem.as_mut_ptr(),
200 __kernel_timespec {
201 tv_sec: old_rem.tv_sec.into(),
202 tv_nsec: old_rem.tv_nsec.into(),
203 },
204 );
205 Ok(())
206}
207
208#[inline]
209pub(crate) fn gettid() -> Pid {
210 unsafe {
211 let tid: i32 = ret_usize_infallible(syscall_readonly!(__NR_gettid)) as __kernel_pid_t;
212 debug_assert_ne!(tid, 0);
213 Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(tid as u32))
214 }
215}
216
217// TODO: This could be de-multiplexed.
218#[inline]
219pub(crate) unsafe fn futex(
220 uaddr: *mut u32,
221 op: FutexOperation,
222 flags: FutexFlags,
223 val: u32,
224 utime: *const Timespec,
225 uaddr2: *mut u32,
226 val3: u32,
227) -> io::Result<usize> {
228 #[cfg(target_pointer_width = "32")]
229 {
230 ret_usize(syscall!(
231 __NR_futex_time64,
232 uaddr,
233 (op, flags),
234 c_uint(val),
235 utime,
236 uaddr2,
237 c_uint(val3)
238 ))
239 .or_else(|err| {
240 // See the comments in `rustix_clock_gettime_via_syscall` about
241 // emulation.
242 if err == io::Errno::NOSYS {
243 futex_old(uaddr, op, flags, val, utime, uaddr2, val3)
244 } else {
245 Err(err)
246 }
247 })
248 }
249 #[cfg(target_pointer_width = "64")]
250 ret_usize(syscall!(
251 __NR_futex,
252 uaddr,
253 (op, flags),
254 c_uint(val),
255 utime,
256 uaddr2,
257 c_uint(val3)
258 ))
259}
260
261#[cfg(target_pointer_width = "32")]
262unsafe fn futex_old(
263 uaddr: *mut u32,
264 op: FutexOperation,
265 flags: FutexFlags,
266 val: u32,
267 utime: *const Timespec,
268 uaddr2: *mut u32,
269 val3: u32,
270) -> io::Result<usize> {
271 let old_utime = __kernel_old_timespec {
272 tv_sec: (*utime).tv_sec.try_into().map_err(|_| io::Errno::INVAL)?,
273 tv_nsec: (*utime).tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
274 };
275 ret_usize(syscall!(
276 __NR_futex,
277 uaddr,
278 (op, flags),
279 c_uint(val),
280 by_ref(&old_utime),
281 uaddr2,
282 c_uint(val3)
283 ))
284}
285
286#[cfg(any(target_os = "android", target_os = "linux"))]
287#[inline]
288pub(crate) fn setns(fd: BorrowedFd, nstype: c::c_int) -> io::Result<c::c_int> {
289 unsafe { ret_c_int(syscall_readonly!(__NR_setns, fd, c_int(nstype))) }
290}
291
292#[cfg(any(target_os = "android", target_os = "linux"))]
293#[inline]
294pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> {
295 unsafe { ret(syscall_readonly!(__NR_unshare, c_uint(flags.bits()))) }
296}