1 | //! linux_raw syscalls supporting `rustix::event`. |
2 | //! |
3 | //! # Safety |
4 | //! |
5 | //! See the `rustix::backend` module documentation for details. |
6 | #![allow (unsafe_code, clippy::undocumented_unsafe_blocks)] |
7 | |
8 | use crate::backend::c; |
9 | use crate::backend::conv::{ |
10 | by_ref, c_int, c_uint, ret, ret_c_int, ret_error, ret_owned_fd, ret_usize, slice_mut, zero, |
11 | }; |
12 | use crate::event::{epoll, EventfdFlags, FdSetElement, PollFd}; |
13 | use crate::fd::{BorrowedFd, OwnedFd}; |
14 | use crate::io; |
15 | use crate::utils::as_mut_ptr; |
16 | #[cfg (feature = "alloc" )] |
17 | use core::mem::MaybeUninit; |
18 | use core::ptr::null_mut; |
19 | use linux_raw_sys::general::{EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD}; |
20 | #[cfg (any(target_arch = "aarch64" , target_arch = "riscv64" ))] |
21 | use { |
22 | crate::backend::conv::{opt_ref, size_of}, |
23 | linux_raw_sys::general::{__kernel_timespec, kernel_sigset_t}, |
24 | }; |
25 | |
26 | #[inline ] |
27 | pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> { |
28 | let (fds_addr_mut, fds_len) = slice_mut(fds); |
29 | |
30 | #[cfg (any(target_arch = "aarch64" , target_arch = "riscv64" ))] |
31 | unsafe { |
32 | let timeout = if timeout >= 0 { |
33 | Some(__kernel_timespec { |
34 | tv_sec: (timeout as i64) / 1000, |
35 | tv_nsec: (timeout as i64) % 1000 * 1_000_000, |
36 | }) |
37 | } else { |
38 | None |
39 | }; |
40 | ret_usize(syscall!( |
41 | __NR_ppoll, |
42 | fds_addr_mut, |
43 | fds_len, |
44 | opt_ref(timeout.as_ref()), |
45 | zero(), |
46 | size_of::<kernel_sigset_t, _>() |
47 | )) |
48 | } |
49 | #[cfg (not(any(target_arch = "aarch64" , target_arch = "riscv64" )))] |
50 | unsafe { |
51 | ret_usize(syscall!(__NR_poll, fds_addr_mut, fds_len, c_int(timeout))) |
52 | } |
53 | } |
54 | |
55 | pub(crate) unsafe fn select( |
56 | nfds: i32, |
57 | readfds: Option<&mut [FdSetElement]>, |
58 | writefds: Option<&mut [FdSetElement]>, |
59 | exceptfds: Option<&mut [FdSetElement]>, |
60 | timeout: Option<&crate::timespec::Timespec>, |
61 | ) -> io::Result<i32> { |
62 | let len = crate::event::fd_set_num_elements_for_bitvector(nfds); |
63 | |
64 | let readfds = match readfds { |
65 | Some(readfds) => { |
66 | assert!(readfds.len() >= len); |
67 | readfds.as_mut_ptr() |
68 | } |
69 | None => null_mut(), |
70 | }; |
71 | let writefds = match writefds { |
72 | Some(writefds) => { |
73 | assert!(writefds.len() >= len); |
74 | writefds.as_mut_ptr() |
75 | } |
76 | None => null_mut(), |
77 | }; |
78 | let exceptfds = match exceptfds { |
79 | Some(exceptfds) => { |
80 | assert!(exceptfds.len() >= len); |
81 | exceptfds.as_mut_ptr() |
82 | } |
83 | None => null_mut(), |
84 | }; |
85 | |
86 | // Linux's `pselect6` mutates the timeout argument. Our public interface |
87 | // does not do this, because it's not portable to other platforms, so we |
88 | // create a temporary value to hide this behavior. |
89 | let mut timeout_data; |
90 | let timeout_ptr = match timeout { |
91 | Some(timeout) => { |
92 | timeout_data = *timeout; |
93 | as_mut_ptr(&mut timeout_data) |
94 | } |
95 | None => null_mut(), |
96 | }; |
97 | |
98 | #[cfg (any( |
99 | target_arch = "arm" , |
100 | target_arch = "powerpc" , |
101 | target_arch = "sparc" , |
102 | target_arch = "csky" , |
103 | target_arch = "x86" , |
104 | target_arch = "mips32r6" , |
105 | target_arch = "riscv32" , |
106 | target_arch = "mips" |
107 | ))] |
108 | { |
109 | ret_c_int(syscall!( |
110 | __NR_pselect6_time64, |
111 | c_int(nfds), |
112 | readfds, |
113 | writefds, |
114 | exceptfds, |
115 | timeout_ptr, |
116 | zero() |
117 | )) |
118 | } |
119 | |
120 | #[cfg (target_pointer_width = "64" )] |
121 | { |
122 | ret_c_int(syscall!( |
123 | __NR_pselect6, |
124 | c_int(nfds), |
125 | readfds, |
126 | writefds, |
127 | exceptfds, |
128 | timeout_ptr, |
129 | zero() |
130 | )) |
131 | } |
132 | } |
133 | |
134 | #[inline ] |
135 | pub(crate) fn epoll_create(flags: epoll::CreateFlags) -> io::Result<OwnedFd> { |
136 | // SAFETY: `__NR_epoll_create1` doesn't access any user memory. |
137 | unsafe { ret_owned_fd(raw:syscall_readonly!(__NR_epoll_create1, flags)) } |
138 | } |
139 | |
140 | #[inline ] |
141 | pub(crate) fn epoll_add( |
142 | epfd: BorrowedFd<'_>, |
143 | fd: BorrowedFd<'_>, |
144 | event: &epoll::Event, |
145 | ) -> io::Result<()> { |
146 | // SAFETY: `__NR_epoll_ctl` with `EPOLL_CTL_ADD` doesn't modify any user |
147 | // memory, and it only reads from `event`. |
148 | unsafe { |
149 | ret(raw:syscall_readonly!( |
150 | __NR_epoll_ctl, |
151 | epfd, |
152 | c_uint(EPOLL_CTL_ADD), |
153 | fd, |
154 | by_ref(event) |
155 | )) |
156 | } |
157 | } |
158 | |
159 | #[inline ] |
160 | pub(crate) fn epoll_mod( |
161 | epfd: BorrowedFd<'_>, |
162 | fd: BorrowedFd<'_>, |
163 | event: &epoll::Event, |
164 | ) -> io::Result<()> { |
165 | // SAFETY: `__NR_epoll_ctl` with `EPOLL_CTL_MOD` doesn't modify any user |
166 | // memory, and it only reads from `event`. |
167 | unsafe { |
168 | ret(raw:syscall_readonly!( |
169 | __NR_epoll_ctl, |
170 | epfd, |
171 | c_uint(EPOLL_CTL_MOD), |
172 | fd, |
173 | by_ref(event) |
174 | )) |
175 | } |
176 | } |
177 | |
178 | #[inline ] |
179 | pub(crate) fn epoll_del(epfd: BorrowedFd<'_>, fd: BorrowedFd<'_>) -> io::Result<()> { |
180 | // SAFETY: `__NR_epoll_ctl` with `EPOLL_CTL_DEL` doesn't access any user |
181 | // memory. |
182 | unsafe { |
183 | ret(raw:syscall_readonly!( |
184 | __NR_epoll_ctl, |
185 | epfd, |
186 | c_uint(EPOLL_CTL_DEL), |
187 | fd, |
188 | zero() |
189 | )) |
190 | } |
191 | } |
192 | |
193 | #[cfg (feature = "alloc" )] |
194 | #[inline ] |
195 | pub(crate) fn epoll_wait( |
196 | epfd: BorrowedFd<'_>, |
197 | events: &mut [MaybeUninit<crate::event::epoll::Event>], |
198 | timeout: c::c_int, |
199 | ) -> io::Result<usize> { |
200 | let (buf_addr_mut, buf_len) = slice_mut(events); |
201 | // SAFETY: `__NR_epoll_wait` doesn't access any user memory outside of |
202 | // the `events` array. |
203 | #[cfg (not(any(target_arch = "aarch64" , target_arch = "riscv64" )))] |
204 | unsafe { |
205 | ret_usize(syscall!( |
206 | __NR_epoll_wait, |
207 | epfd, |
208 | buf_addr_mut, |
209 | buf_len, |
210 | c_int(timeout) |
211 | )) |
212 | } |
213 | // SAFETY: `__NR_epoll_pwait` doesn't access any user memory outside of |
214 | // the `events` array, as we don't pass it a `sigmask`. |
215 | #[cfg (any(target_arch = "aarch64" , target_arch = "riscv64" ))] |
216 | unsafe { |
217 | ret_usize(syscall!( |
218 | __NR_epoll_pwait, |
219 | epfd, |
220 | buf_addr_mut, |
221 | buf_len, |
222 | c_int(timeout), |
223 | zero() |
224 | )) |
225 | } |
226 | } |
227 | |
228 | #[inline ] |
229 | pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { |
230 | unsafe { ret_owned_fd(raw:syscall_readonly!(__NR_eventfd2, c_uint(initval), flags)) } |
231 | } |
232 | |
233 | #[inline ] |
234 | pub(crate) fn pause() { |
235 | unsafe { |
236 | #[cfg (any(target_arch = "aarch64" , target_arch = "riscv64" ))] |
237 | let error = ret_error(syscall_readonly!( |
238 | __NR_ppoll, |
239 | zero(), |
240 | zero(), |
241 | zero(), |
242 | zero() |
243 | )); |
244 | |
245 | #[cfg (not(any(target_arch = "aarch64" , target_arch = "riscv64" )))] |
246 | let error: Errno = ret_error(raw:syscall_readonly!(__NR_pause)); |
247 | |
248 | debug_assert_eq!(error, io::Errno::INTR); |
249 | } |
250 | } |
251 | |