• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
9 use super::super::c;
10 use super::super::conv::{
11     by_ref, c_int, c_uint, ret, ret_c_int, ret_usize, ret_usize_infallible, zero,
12 };
13 use crate::fd::BorrowedFd;
14 use crate::io;
15 use crate::process::{Pid, RawNonZeroPid};
16 use crate::thread::{ClockId, FutexFlags, FutexOperation, NanosleepRelativeResult, Timespec};
17 use core::mem::MaybeUninit;
18 use linux_raw_sys::general::{__kernel_pid_t, __kernel_timespec, TIMER_ABSTIME};
19 #[cfg(target_pointer_width = "32")]
20 use {
21     core::convert::TryInto, core::ptr, linux_raw_sys::general::timespec as __kernel_old_timespec,
22 };
23 
24 #[inline]
clock_nanosleep_relative( id: ClockId, req: &__kernel_timespec, ) -> NanosleepRelativeResult25 pub(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")]
clock_nanosleep_relative_old( id: ClockId, req: &__kernel_timespec, rem: &mut MaybeUninit<__kernel_timespec>, ) -> io::Result<()>71 unsafe 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]
clock_nanosleep_absolute(id: ClockId, req: &__kernel_timespec) -> io::Result<()>101 pub(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")]
clock_nanosleep_absolute_old(id: ClockId, req: &__kernel_timespec) -> io::Result<()>134 unsafe 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]
nanosleep(req: &__kernel_timespec) -> NanosleepRelativeResult149 pub(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")]
nanosleep_old( req: &__kernel_timespec, rem: &mut MaybeUninit<__kernel_timespec>, ) -> io::Result<()>186 unsafe 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]
gettid() -> Pid209 pub(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]
futex( uaddr: *mut u32, op: FutexOperation, flags: FutexFlags, val: u32, utime: *const Timespec, uaddr2: *mut u32, val3: u32, ) -> io::Result<usize>219 pub(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")]
futex_old( uaddr: *mut u32, op: FutexOperation, flags: FutexFlags, val: u32, utime: *const Timespec, uaddr2: *mut u32, val3: u32, ) -> io::Result<usize>262 unsafe 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]
setns(fd: BorrowedFd, nstype: c::c_int) -> io::Result<c::c_int>288 pub(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]
unshare(flags: crate::thread::UnshareFlags) -> io::Result<()>294 pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> {
295     unsafe { ret(syscall_readonly!(__NR_unshare, c_uint(flags.bits()))) }
296 }
297