]> git.proxmox.com Git - rustc.git/blob - vendor/rustix-0.37.6/src/backend/libc/thread/syscalls.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / vendor / rustix-0.37.6 / src / backend / libc / thread / syscalls.rs
1 //! libc syscalls supporting `rustix::thread`.
2
3 use super::super::c;
4 use super::super::conv::ret;
5 #[cfg(any(target_os = "android", target_os = "linux"))]
6 use super::super::conv::{borrowed_fd, ret_c_int, syscall_ret};
7 use super::super::time::types::LibcTimespec;
8 #[cfg(any(target_os = "android", target_os = "linux"))]
9 use crate::fd::BorrowedFd;
10 use crate::io;
11 #[cfg(any(target_os = "android", target_os = "linux"))]
12 use crate::process::{Pid, RawNonZeroPid};
13 #[cfg(not(target_os = "redox"))]
14 use crate::thread::{NanosleepRelativeResult, Timespec};
15 use core::mem::MaybeUninit;
16 #[cfg(not(any(
17 apple,
18 freebsdlike,
19 target_os = "emscripten",
20 target_os = "haiku",
21 target_os = "openbsd",
22 target_os = "redox",
23 target_os = "wasi",
24 )))]
25 use {crate::thread::ClockId, core::ptr::null_mut};
26
27 #[cfg(all(
28 any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
29 target_env = "gnu",
30 ))]
31 weak!(fn __clock_nanosleep_time64(c::clockid_t, c::c_int, *const LibcTimespec, *mut LibcTimespec) -> c::c_int);
32 #[cfg(all(
33 any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
34 target_env = "gnu",
35 ))]
36 weak!(fn __nanosleep64(*const LibcTimespec, *mut LibcTimespec) -> c::c_int);
37
38 #[cfg(not(any(
39 apple,
40 target_os = "dragonfly",
41 target_os = "emscripten",
42 target_os = "freebsd", // FreeBSD 12 has clock_nanosleep, but libc targets FreeBSD 11.
43 target_os = "haiku",
44 target_os = "openbsd",
45 target_os = "redox",
46 target_os = "wasi",
47 )))]
48 #[inline]
49 pub(crate) fn clock_nanosleep_relative(id: ClockId, request: &Timespec) -> NanosleepRelativeResult {
50 let mut remain = MaybeUninit::<LibcTimespec>::uninit();
51 let flags = 0;
52
53 // 32-bit gnu version: libc has `clock_nanosleep` but it is not y2038 safe by
54 // default.
55 #[cfg(all(
56 any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
57 target_env = "gnu",
58 ))]
59 unsafe {
60 if let Some(libc_clock_nanosleep) = __clock_nanosleep_time64.get() {
61 match libc_clock_nanosleep(
62 id as c::clockid_t,
63 flags,
64 &request.clone().into(),
65 remain.as_mut_ptr(),
66 ) {
67 0 => NanosleepRelativeResult::Ok,
68 err if err == io::Errno::INTR.0 => {
69 NanosleepRelativeResult::Interrupted(remain.assume_init().into())
70 }
71 err => NanosleepRelativeResult::Err(io::Errno(err)),
72 }
73 } else {
74 clock_nanosleep_relative_old(id, request)
75 }
76 }
77
78 // Main version: libc is y2038 safe and has `clock_nanosleep`.
79 #[cfg(not(all(
80 any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
81 target_env = "gnu",
82 )))]
83 unsafe {
84 match c::clock_nanosleep(id as c::clockid_t, flags, request, remain.as_mut_ptr()) {
85 0 => NanosleepRelativeResult::Ok,
86 err if err == io::Errno::INTR.0 => {
87 NanosleepRelativeResult::Interrupted(remain.assume_init())
88 }
89 err => NanosleepRelativeResult::Err(io::Errno(err)),
90 }
91 }
92 }
93
94 #[cfg(all(
95 any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
96 target_env = "gnu",
97 ))]
98 unsafe fn clock_nanosleep_relative_old(id: ClockId, request: &Timespec) -> NanosleepRelativeResult {
99 use core::convert::TryInto;
100 let tv_sec = match request.tv_sec.try_into() {
101 Ok(tv_sec) => tv_sec,
102 Err(_) => return NanosleepRelativeResult::Err(io::Errno::OVERFLOW),
103 };
104 let tv_nsec = match request.tv_nsec.try_into() {
105 Ok(tv_nsec) => tv_nsec,
106 Err(_) => return NanosleepRelativeResult::Err(io::Errno::INVAL),
107 };
108 let old_request = c::timespec { tv_sec, tv_nsec };
109 let mut old_remain = MaybeUninit::<c::timespec>::uninit();
110 let flags = 0;
111
112 match c::clock_nanosleep(
113 id as c::clockid_t,
114 flags,
115 &old_request,
116 old_remain.as_mut_ptr(),
117 ) {
118 0 => NanosleepRelativeResult::Ok,
119 err if err == io::Errno::INTR.0 => {
120 let old_remain = old_remain.assume_init();
121 let remain = Timespec {
122 tv_sec: old_remain.tv_sec.into(),
123 tv_nsec: old_remain.tv_nsec.into(),
124 };
125 NanosleepRelativeResult::Interrupted(remain)
126 }
127 err => NanosleepRelativeResult::Err(io::Errno(err)),
128 }
129 }
130
131 #[cfg(not(any(
132 apple,
133 target_os = "dragonfly",
134 target_os = "emscripten",
135 target_os = "freebsd", // FreeBSD 12 has clock_nanosleep, but libc targets FreeBSD 11.
136 target_os = "haiku",
137 target_os = "openbsd",
138 target_os = "redox",
139 target_os = "wasi",
140 )))]
141 #[inline]
142 pub(crate) fn clock_nanosleep_absolute(id: ClockId, request: &Timespec) -> io::Result<()> {
143 let flags = c::TIMER_ABSTIME;
144
145 // 32-bit gnu version: libc has `clock_nanosleep` but it is not y2038 safe by
146 // default.
147 #[cfg(all(
148 any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
149 target_env = "gnu",
150 ))]
151 {
152 if let Some(libc_clock_nanosleep) = __clock_nanosleep_time64.get() {
153 match unsafe {
154 libc_clock_nanosleep(
155 id as c::clockid_t,
156 flags,
157 &request.clone().into(),
158 null_mut(),
159 )
160 } {
161 0 => Ok(()),
162 err => Err(io::Errno(err)),
163 }
164 } else {
165 clock_nanosleep_absolute_old(id, request)
166 }
167 }
168
169 // Main version: libc is y2038 safe and has `clock_nanosleep`.
170 #[cfg(not(all(
171 any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
172 target_env = "gnu",
173 )))]
174 match unsafe { c::clock_nanosleep(id as c::clockid_t, flags, request, null_mut()) } {
175 0 => Ok(()),
176 err => Err(io::Errno(err)),
177 }
178 }
179
180 #[cfg(all(
181 any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
182 target_env = "gnu",
183 ))]
184 fn clock_nanosleep_absolute_old(id: ClockId, request: &Timespec) -> io::Result<()> {
185 use core::convert::TryInto;
186
187 let flags = c::TIMER_ABSTIME;
188
189 let old_request = c::timespec {
190 tv_sec: request.tv_sec.try_into().map_err(|_| io::Errno::OVERFLOW)?,
191 tv_nsec: request.tv_nsec.try_into().map_err(|_| io::Errno::INVAL)?,
192 };
193 match unsafe { c::clock_nanosleep(id as c::clockid_t, flags, &old_request, null_mut()) } {
194 0 => Ok(()),
195 err => Err(io::Errno(err)),
196 }
197 }
198
199 #[cfg(not(target_os = "redox"))]
200 #[inline]
201 pub(crate) fn nanosleep(request: &Timespec) -> NanosleepRelativeResult {
202 let mut remain = MaybeUninit::<LibcTimespec>::uninit();
203
204 // 32-bit gnu version: libc has `nanosleep` but it is not y2038 safe by
205 // default.
206 #[cfg(all(
207 any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
208 target_env = "gnu",
209 ))]
210 unsafe {
211 if let Some(libc_nanosleep) = __nanosleep64.get() {
212 match ret(libc_nanosleep(&request.clone().into(), remain.as_mut_ptr())) {
213 Ok(()) => NanosleepRelativeResult::Ok,
214 Err(io::Errno::INTR) => {
215 NanosleepRelativeResult::Interrupted(remain.assume_init().into())
216 }
217 Err(err) => NanosleepRelativeResult::Err(err),
218 }
219 } else {
220 nanosleep_old(request)
221 }
222 }
223
224 // Main version: libc is y2038 safe and has `nanosleep`.
225 #[cfg(not(all(
226 any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
227 target_env = "gnu",
228 )))]
229 unsafe {
230 match ret(c::nanosleep(request, remain.as_mut_ptr())) {
231 Ok(()) => NanosleepRelativeResult::Ok,
232 Err(io::Errno::INTR) => NanosleepRelativeResult::Interrupted(remain.assume_init()),
233 Err(err) => NanosleepRelativeResult::Err(err),
234 }
235 }
236 }
237
238 #[cfg(all(
239 any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
240 target_env = "gnu",
241 ))]
242 unsafe fn nanosleep_old(request: &Timespec) -> NanosleepRelativeResult {
243 use core::convert::TryInto;
244 let tv_sec = match request.tv_sec.try_into() {
245 Ok(tv_sec) => tv_sec,
246 Err(_) => return NanosleepRelativeResult::Err(io::Errno::OVERFLOW),
247 };
248 let tv_nsec = match request.tv_nsec.try_into() {
249 Ok(tv_nsec) => tv_nsec,
250 Err(_) => return NanosleepRelativeResult::Err(io::Errno::INVAL),
251 };
252 let old_request = c::timespec { tv_sec, tv_nsec };
253 let mut old_remain = MaybeUninit::<c::timespec>::uninit();
254
255 match ret(c::nanosleep(&old_request, old_remain.as_mut_ptr())) {
256 Ok(()) => NanosleepRelativeResult::Ok,
257 Err(io::Errno::INTR) => {
258 let old_remain = old_remain.assume_init();
259 let remain = Timespec {
260 tv_sec: old_remain.tv_sec.into(),
261 tv_nsec: old_remain.tv_nsec.into(),
262 };
263 NanosleepRelativeResult::Interrupted(remain)
264 }
265 Err(err) => NanosleepRelativeResult::Err(err),
266 }
267 }
268
269 #[cfg(any(target_os = "android", target_os = "linux"))]
270 #[inline]
271 #[must_use]
272 pub(crate) fn gettid() -> Pid {
273 // `gettid` wasn't supported in glibc until 2.30, and musl until 1.2.2,
274 // so use `syscall`.
275 // <https://sourceware.org/bugzilla/show_bug.cgi?id=6399#c62>
276 weak_or_syscall! {
277 fn gettid() via SYS_gettid -> c::pid_t
278 }
279
280 unsafe {
281 let tid = gettid();
282 debug_assert_ne!(tid, 0);
283 Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(tid))
284 }
285 }
286
287 #[cfg(any(target_os = "android", target_os = "linux"))]
288 #[inline]
289 pub(crate) fn setns(fd: BorrowedFd, nstype: c::c_int) -> io::Result<c::c_int> {
290 // `setns` wasn't supported in glibc until 2.14, and musl until 0.9.5,
291 // so use `syscall`.
292 weak_or_syscall! {
293 fn setns(fd: c::c_int, nstype: c::c_int) via SYS_setns -> c::c_int
294 }
295
296 unsafe { ret_c_int(setns(borrowed_fd(fd), nstype)) }
297 }
298
299 #[cfg(any(target_os = "android", target_os = "linux"))]
300 #[inline]
301 pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> {
302 unsafe { ret(c::unshare(flags.bits() as i32)) }
303 }
304
305 #[cfg(any(target_os = "android", target_os = "linux"))]
306 #[inline]
307 pub(crate) fn capget(
308 header: &mut linux_raw_sys::general::__user_cap_header_struct,
309 data: &mut [MaybeUninit<linux_raw_sys::general::__user_cap_data_struct>],
310 ) -> io::Result<()> {
311 let header: *mut _ = header;
312 unsafe { syscall_ret(c::syscall(c::SYS_capget, header, data.as_mut_ptr())) }
313 }
314
315 #[cfg(any(target_os = "android", target_os = "linux"))]
316 #[inline]
317 pub(crate) fn capset(
318 header: &mut linux_raw_sys::general::__user_cap_header_struct,
319 data: &[linux_raw_sys::general::__user_cap_data_struct],
320 ) -> io::Result<()> {
321 let header: *mut _ = header;
322 unsafe { syscall_ret(c::syscall(c::SYS_capset, header, data.as_ptr())) }
323 }
324
325 #[cfg(any(target_os = "android", target_os = "linux"))]
326 #[inline]
327 pub(crate) fn setuid_thread(uid: crate::process::Uid) -> io::Result<()> {
328 unsafe { syscall_ret(c::syscall(c::SYS_setuid, uid.as_raw())) }
329 }
330
331 #[cfg(any(target_os = "android", target_os = "linux"))]
332 #[inline]
333 pub(crate) fn setresuid_thread(
334 ruid: crate::process::Uid,
335 euid: crate::process::Uid,
336 suid: crate::process::Uid,
337 ) -> io::Result<()> {
338 #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
339 const SYS: c::c_long = c::SYS_setresuid32 as c::c_long;
340 #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
341 const SYS: c::c_long = c::SYS_setresuid as c::c_long;
342 unsafe { syscall_ret(c::syscall(SYS, ruid.as_raw(), euid.as_raw(), suid.as_raw())) }
343 }
344
345 #[cfg(any(target_os = "android", target_os = "linux"))]
346 #[inline]
347 pub(crate) fn setgid_thread(gid: crate::process::Gid) -> io::Result<()> {
348 unsafe { syscall_ret(c::syscall(c::SYS_setgid, gid.as_raw())) }
349 }
350
351 #[cfg(any(target_os = "android", target_os = "linux"))]
352 #[inline]
353 pub(crate) fn setresgid_thread(
354 rgid: crate::process::Gid,
355 egid: crate::process::Gid,
356 sgid: crate::process::Gid,
357 ) -> io::Result<()> {
358 #[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc"))]
359 const SYS: c::c_long = c::SYS_setresgid32 as c::c_long;
360 #[cfg(not(any(target_arch = "x86", target_arch = "arm", target_arch = "sparc")))]
361 const SYS: c::c_long = c::SYS_setresgid as c::c_long;
362 unsafe { syscall_ret(c::syscall(SYS, rgid.as_raw(), egid.as_raw(), sgid.as_raw())) }
363 }