1 | //! linux_raw syscalls supporting `rustix::io`. |
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 | #[cfg (target_pointer_width = "64" )] |
11 | use super::super::conv::loff_t_from_u64; |
12 | use super::super::conv::{ |
13 | by_ref, c_int, c_uint, opt_mut, pass_usize, raw_fd, ret, ret_c_uint, ret_discarded_fd, |
14 | ret_owned_fd, ret_usize, slice, slice_mut, zero, |
15 | }; |
16 | #[cfg (target_pointer_width = "32" )] |
17 | use super::super::conv::{hi, lo}; |
18 | use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd}; |
19 | #[cfg (linux_kernel)] |
20 | use crate::io::SpliceFlags; |
21 | use crate::io::{ |
22 | self, epoll, DupFlags, EventfdFlags, FdFlags, IoSlice, IoSliceMut, IoSliceRaw, PipeFlags, |
23 | PollFd, ReadWriteFlags, |
24 | }; |
25 | #[cfg (all(feature = "fs" , feature = "net" ))] |
26 | use crate::net::{RecvFlags, SendFlags}; |
27 | use core::cmp; |
28 | use core::mem::MaybeUninit; |
29 | #[cfg (target_os = "espidf" )] |
30 | use linux_raw_sys::general::F_DUPFD; |
31 | use linux_raw_sys::general::{ |
32 | epoll_event, EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD, F_DUPFD_CLOEXEC, F_GETFD, F_SETFD, |
33 | UIO_MAXIOV, |
34 | }; |
35 | use linux_raw_sys::ioctl::{ |
36 | BLKPBSZGET, BLKSSZGET, EXT4_IOC_RESIZE_FS, FICLONE, FIONBIO, FIONREAD, TIOCEXCL, TIOCNXCL, |
37 | }; |
38 | #[cfg (any(target_arch = "aarch64" , target_arch = "riscv64" ))] |
39 | use { |
40 | super::super::conv::{opt_ref, size_of}, |
41 | linux_raw_sys::general::{__kernel_timespec, kernel_sigset_t}, |
42 | }; |
43 | |
44 | #[inline ] |
45 | pub(crate) fn read(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> { |
46 | let (buf_addr_mut: ArgReg<'_, A1>, buf_len: ArgReg<'_, A2>) = slice_mut(buf); |
47 | |
48 | unsafe { ret_usize(raw:syscall!(__NR_read, fd, buf_addr_mut, buf_len)) } |
49 | } |
50 | |
51 | #[inline ] |
52 | pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], pos: u64) -> io::Result<usize> { |
53 | let (buf_addr_mut, buf_len) = slice_mut(buf); |
54 | |
55 | // <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L75> |
56 | #[cfg (all( |
57 | target_pointer_width = "32" , |
58 | any(target_arch = "arm" , target_arch = "mips" , target_arch = "power" ), |
59 | ))] |
60 | unsafe { |
61 | ret_usize(syscall!( |
62 | __NR_pread64, |
63 | fd, |
64 | buf_addr_mut, |
65 | buf_len, |
66 | zero(), |
67 | hi(pos), |
68 | lo(pos) |
69 | )) |
70 | } |
71 | #[cfg (all( |
72 | target_pointer_width = "32" , |
73 | not(any(target_arch = "arm" , target_arch = "mips" , target_arch = "power" )), |
74 | ))] |
75 | unsafe { |
76 | ret_usize(syscall!( |
77 | __NR_pread64, |
78 | fd, |
79 | buf_addr_mut, |
80 | buf_len, |
81 | hi(pos), |
82 | lo(pos) |
83 | )) |
84 | } |
85 | #[cfg (target_pointer_width = "64" )] |
86 | unsafe { |
87 | ret_usize(syscall!( |
88 | __NR_pread64, |
89 | fd, |
90 | buf_addr_mut, |
91 | buf_len, |
92 | loff_t_from_u64(pos) |
93 | )) |
94 | } |
95 | } |
96 | |
97 | #[inline ] |
98 | pub(crate) fn readv(fd: BorrowedFd<'_>, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
99 | let (bufs_addr: ArgReg<'_, A1>, bufs_len: ArgReg<'_, A2>) = slice(&bufs[..cmp::min(v1:bufs.len(), v2:max_iov())]); |
100 | |
101 | unsafe { ret_usize(raw:syscall!(__NR_readv, fd, bufs_addr, bufs_len)) } |
102 | } |
103 | |
104 | #[inline ] |
105 | pub(crate) fn preadv( |
106 | fd: BorrowedFd<'_>, |
107 | bufs: &mut [IoSliceMut<'_>], |
108 | pos: u64, |
109 | ) -> io::Result<usize> { |
110 | let (bufs_addr: ArgReg<'_, A1>, bufs_len: ArgReg<'_, A2>) = slice(&bufs[..cmp::min(v1:bufs.len(), v2:max_iov())]); |
111 | |
112 | // Unlike the plain "p" functions, the "pv" functions pass their offset in |
113 | // an endian-independent way, and always in two registers. |
114 | unsafe { |
115 | ret_usize(raw:syscall!( |
116 | __NR_preadv, |
117 | fd, |
118 | bufs_addr, |
119 | bufs_len, |
120 | pass_usize(pos as usize), |
121 | pass_usize((pos >> 32) as usize) |
122 | )) |
123 | } |
124 | } |
125 | |
126 | #[inline ] |
127 | pub(crate) fn preadv2( |
128 | fd: BorrowedFd<'_>, |
129 | bufs: &mut [IoSliceMut<'_>], |
130 | pos: u64, |
131 | flags: ReadWriteFlags, |
132 | ) -> io::Result<usize> { |
133 | let (bufs_addr: ArgReg<'_, A1>, bufs_len: ArgReg<'_, A2>) = slice(&bufs[..cmp::min(v1:bufs.len(), v2:max_iov())]); |
134 | |
135 | // Unlike the plain "p" functions, the "pv" functions pass their offset in |
136 | // an endian-independent way, and always in two registers. |
137 | unsafe { |
138 | ret_usize(raw:syscall!( |
139 | __NR_preadv2, |
140 | fd, |
141 | bufs_addr, |
142 | bufs_len, |
143 | pass_usize(pos as usize), |
144 | pass_usize((pos >> 32) as usize), |
145 | flags |
146 | )) |
147 | } |
148 | } |
149 | |
150 | #[inline ] |
151 | pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> { |
152 | let (buf_addr: ArgReg<'_, A1>, buf_len: ArgReg<'_, A2>) = slice(buf); |
153 | |
154 | unsafe { ret_usize(raw:syscall_readonly!(__NR_write, fd, buf_addr, buf_len)) } |
155 | } |
156 | |
157 | #[inline ] |
158 | pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], pos: u64) -> io::Result<usize> { |
159 | let (buf_addr, buf_len) = slice(buf); |
160 | |
161 | // <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L81-L83> |
162 | #[cfg (all( |
163 | target_pointer_width = "32" , |
164 | any(target_arch = "arm" , target_arch = "mips" , target_arch = "power" ), |
165 | ))] |
166 | unsafe { |
167 | ret_usize(syscall_readonly!( |
168 | __NR_pwrite64, |
169 | fd, |
170 | buf_addr, |
171 | buf_len, |
172 | zero(), |
173 | hi(pos), |
174 | lo(pos) |
175 | )) |
176 | } |
177 | #[cfg (all( |
178 | target_pointer_width = "32" , |
179 | not(any(target_arch = "arm" , target_arch = "mips" , target_arch = "power" )), |
180 | ))] |
181 | unsafe { |
182 | ret_usize(syscall_readonly!( |
183 | __NR_pwrite64, |
184 | fd, |
185 | buf_addr, |
186 | buf_len, |
187 | hi(pos), |
188 | lo(pos) |
189 | )) |
190 | } |
191 | #[cfg (target_pointer_width = "64" )] |
192 | unsafe { |
193 | ret_usize(syscall_readonly!( |
194 | __NR_pwrite64, |
195 | fd, |
196 | buf_addr, |
197 | buf_len, |
198 | loff_t_from_u64(pos) |
199 | )) |
200 | } |
201 | } |
202 | |
203 | #[inline ] |
204 | pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
205 | let (bufs_addr: ArgReg<'_, A1>, bufs_len: ArgReg<'_, A2>) = slice(&bufs[..cmp::min(v1:bufs.len(), v2:max_iov())]); |
206 | |
207 | unsafe { ret_usize(raw:syscall_readonly!(__NR_writev, fd, bufs_addr, bufs_len)) } |
208 | } |
209 | |
210 | #[inline ] |
211 | pub(crate) fn pwritev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>], pos: u64) -> io::Result<usize> { |
212 | let (bufs_addr: ArgReg<'_, A1>, bufs_len: ArgReg<'_, A2>) = slice(&bufs[..cmp::min(v1:bufs.len(), v2:max_iov())]); |
213 | |
214 | // Unlike the plain "p" functions, the "pv" functions pass their offset in |
215 | // an endian-independent way, and always in two registers. |
216 | unsafe { |
217 | ret_usize(raw:syscall_readonly!( |
218 | __NR_pwritev, |
219 | fd, |
220 | bufs_addr, |
221 | bufs_len, |
222 | pass_usize(pos as usize), |
223 | pass_usize((pos >> 32) as usize) |
224 | )) |
225 | } |
226 | } |
227 | |
228 | #[inline ] |
229 | pub(crate) fn pwritev2( |
230 | fd: BorrowedFd<'_>, |
231 | bufs: &[IoSlice<'_>], |
232 | pos: u64, |
233 | flags: ReadWriteFlags, |
234 | ) -> io::Result<usize> { |
235 | let (bufs_addr: ArgReg<'_, A1>, bufs_len: ArgReg<'_, A2>) = slice(&bufs[..cmp::min(v1:bufs.len(), v2:max_iov())]); |
236 | |
237 | // Unlike the plain "p" functions, the "pv" functions pass their offset in |
238 | // an endian-independent way, and always in two registers. |
239 | unsafe { |
240 | ret_usize(raw:syscall_readonly!( |
241 | __NR_pwritev2, |
242 | fd, |
243 | bufs_addr, |
244 | bufs_len, |
245 | pass_usize(pos as usize), |
246 | pass_usize((pos >> 32) as usize), |
247 | flags |
248 | )) |
249 | } |
250 | } |
251 | |
252 | /// The maximum number of buffers that can be passed into a vectored I/O system |
253 | /// call on the current platform. |
254 | const fn max_iov() -> usize { |
255 | UIO_MAXIOV as usize |
256 | } |
257 | |
258 | #[inline ] |
259 | pub(crate) unsafe fn close(fd: RawFd) { |
260 | // See the documentation for [`io::close`] for why errors are ignored. |
261 | syscall_readonly!(__NR_close, raw_fd(fd)).decode_void(); |
262 | } |
263 | |
264 | #[inline ] |
265 | pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { |
266 | unsafe { ret_owned_fd(raw:syscall_readonly!(__NR_eventfd2, c_uint(initval), flags)) } |
267 | } |
268 | |
269 | #[inline ] |
270 | pub(crate) fn ioctl_fionread(fd: BorrowedFd<'_>) -> io::Result<u64> { |
271 | unsafe { |
272 | let mut result: MaybeUninit = MaybeUninit::<c::c_int>::uninit(); |
273 | ret(raw:syscall!(__NR_ioctl, fd, c_uint(FIONREAD), &mut result))?; |
274 | Ok(result.assume_init() as u64) |
275 | } |
276 | } |
277 | |
278 | #[inline ] |
279 | pub(crate) fn ioctl_fionbio(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { |
280 | unsafe { |
281 | let data: i32 = c::c_int::from(value); |
282 | ret(raw:syscall_readonly!( |
283 | __NR_ioctl, |
284 | fd, |
285 | c_uint(FIONBIO), |
286 | by_ref(&data) |
287 | )) |
288 | } |
289 | } |
290 | |
291 | #[inline ] |
292 | pub(crate) fn ioctl_tiocexcl(fd: BorrowedFd<'_>) -> io::Result<()> { |
293 | unsafe { ret(raw:syscall_readonly!(__NR_ioctl, fd, c_uint(TIOCEXCL))) } |
294 | } |
295 | |
296 | #[inline ] |
297 | pub(crate) fn ioctl_tiocnxcl(fd: BorrowedFd<'_>) -> io::Result<()> { |
298 | unsafe { ret(raw:syscall_readonly!(__NR_ioctl, fd, c_uint(TIOCNXCL))) } |
299 | } |
300 | |
301 | #[inline ] |
302 | pub(crate) fn ioctl_blksszget(fd: BorrowedFd) -> io::Result<u32> { |
303 | let mut result: MaybeUninit = MaybeUninit::<c::c_uint>::uninit(); |
304 | unsafe { |
305 | ret(raw:syscall!(__NR_ioctl, fd, c_uint(BLKSSZGET), &mut result))?; |
306 | Ok(result.assume_init() as u32) |
307 | } |
308 | } |
309 | |
310 | #[inline ] |
311 | pub(crate) fn ioctl_blkpbszget(fd: BorrowedFd) -> io::Result<u32> { |
312 | let mut result: MaybeUninit = MaybeUninit::<c::c_uint>::uninit(); |
313 | unsafe { |
314 | ret(raw:syscall!(__NR_ioctl, fd, c_uint(BLKPBSZGET), &mut result))?; |
315 | Ok(result.assume_init() as u32) |
316 | } |
317 | } |
318 | |
319 | #[inline ] |
320 | pub(crate) fn ioctl_ficlone(fd: BorrowedFd<'_>, src_fd: BorrowedFd<'_>) -> io::Result<()> { |
321 | unsafe { ret(raw:syscall_readonly!(__NR_ioctl, fd, c_uint(FICLONE), src_fd)) } |
322 | } |
323 | |
324 | #[inline ] |
325 | pub(crate) fn ext4_ioc_resize_fs(fd: BorrowedFd<'_>, blocks: u64) -> io::Result<()> { |
326 | unsafe { |
327 | ret(raw:syscall_readonly!( |
328 | __NR_ioctl, |
329 | fd, |
330 | c_uint(EXT4_IOC_RESIZE_FS), |
331 | by_ref(&blocks) |
332 | )) |
333 | } |
334 | } |
335 | |
336 | #[cfg (all(feature = "fs" , feature = "net" ))] |
337 | pub(crate) fn is_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { |
338 | let (mut read, mut write) = crate::fs::fd::_is_file_read_write(fd)?; |
339 | let mut not_socket = false; |
340 | if read { |
341 | // Do a `recv` with `PEEK` and `DONTWAIT` for 1 byte. A 0 indicates |
342 | // the read side is shut down; an `EWOULDBLOCK` indicates the read |
343 | // side is still open. |
344 | // |
345 | // TODO: This code would benefit from having a better way to read into |
346 | // uninitialized memory. |
347 | let mut buf = [0]; |
348 | match super::super::net::syscalls::recv(fd, &mut buf, RecvFlags::PEEK | RecvFlags::DONTWAIT) |
349 | { |
350 | Ok(0) => read = false, |
351 | Err(err) => { |
352 | #[allow (unreachable_patterns)] // `EAGAIN` may equal `EWOULDBLOCK` |
353 | match err { |
354 | io::Errno::AGAIN | io::Errno::WOULDBLOCK => (), |
355 | io::Errno::NOTSOCK => not_socket = true, |
356 | _ => return Err(err), |
357 | } |
358 | } |
359 | Ok(_) => (), |
360 | } |
361 | } |
362 | if write && !not_socket { |
363 | // Do a `send` with `DONTWAIT` for 0 bytes. An `EPIPE` indicates |
364 | // the write side is shut down. |
365 | #[allow (unreachable_patterns)] // `EAGAIN` equals `EWOULDBLOCK` |
366 | match super::super::net::syscalls::send(fd, &[], SendFlags::DONTWAIT) { |
367 | // TODO or-patterns when we don't need 1.51 |
368 | Err(io::Errno::AGAIN) => (), |
369 | Err(io::Errno::WOULDBLOCK) => (), |
370 | Err(io::Errno::NOTSOCK) => (), |
371 | Err(io::Errno::PIPE) => write = false, |
372 | Err(err) => return Err(err), |
373 | Ok(_) => (), |
374 | } |
375 | } |
376 | Ok((read, write)) |
377 | } |
378 | |
379 | #[inline ] |
380 | pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> { |
381 | unsafe { ret_owned_fd(raw:syscall_readonly!(__NR_dup, fd)) } |
382 | } |
383 | |
384 | #[inline ] |
385 | pub(crate) fn dup2(fd: BorrowedFd<'_>, new: &mut OwnedFd) -> io::Result<()> { |
386 | #[cfg (any(target_arch = "aarch64" , target_arch = "riscv64" ))] |
387 | { |
388 | // We don't need to worry about the difference between `dup2` and |
389 | // `dup3` when the file descriptors are equal because we have an |
390 | // `&mut OwnedFd` which means `fd` doesn't alias it. |
391 | dup3(fd, new, DupFlags::empty()) |
392 | } |
393 | |
394 | #[cfg (not(any(target_arch = "aarch64" , target_arch = "riscv64" )))] |
395 | unsafe { |
396 | ret_discarded_fd(raw:syscall_readonly!(__NR_dup2, fd, new.as_fd())) |
397 | } |
398 | } |
399 | |
400 | #[inline ] |
401 | pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, flags: DupFlags) -> io::Result<()> { |
402 | unsafe { ret_discarded_fd(raw:syscall_readonly!(__NR_dup3, fd, new.as_fd(), flags)) } |
403 | } |
404 | |
405 | #[inline ] |
406 | pub(crate) fn fcntl_getfd(fd: BorrowedFd<'_>) -> io::Result<FdFlags> { |
407 | #[cfg (target_pointer_width = "32" )] |
408 | unsafe { |
409 | ret_c_uint(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETFD))) |
410 | .map(FdFlags::from_bits_truncate) |
411 | } |
412 | #[cfg (target_pointer_width = "64" )] |
413 | unsafe { |
414 | ret_c_uint(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETFD))) |
415 | .map(op:FdFlags::from_bits_truncate) |
416 | } |
417 | } |
418 | |
419 | #[inline ] |
420 | pub(crate) fn fcntl_setfd(fd: BorrowedFd<'_>, flags: FdFlags) -> io::Result<()> { |
421 | #[cfg (target_pointer_width = "32" )] |
422 | unsafe { |
423 | ret(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_SETFD), flags)) |
424 | } |
425 | #[cfg (target_pointer_width = "64" )] |
426 | unsafe { |
427 | ret(raw:syscall_readonly!(__NR_fcntl, fd, c_uint(F_SETFD), flags)) |
428 | } |
429 | } |
430 | |
431 | #[cfg (target_os = "espidf" )] |
432 | #[inline ] |
433 | pub(crate) fn fcntl_dupfd(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> { |
434 | #[cfg (target_pointer_width = "32" )] |
435 | unsafe { |
436 | ret_owned_fd(syscall_readonly!( |
437 | __NR_fcntl64, |
438 | fd, |
439 | c_uint(F_DUPFD), |
440 | raw_fd(min) |
441 | )) |
442 | } |
443 | #[cfg (target_pointer_width = "64" )] |
444 | unsafe { |
445 | ret_owned_fd(syscall_readonly!( |
446 | __NR_fcntl, |
447 | fd, |
448 | c_uint(F_DUPFD), |
449 | raw_fd(min) |
450 | )) |
451 | } |
452 | } |
453 | |
454 | #[inline ] |
455 | pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> { |
456 | #[cfg (target_pointer_width = "32" )] |
457 | unsafe { |
458 | ret_owned_fd(syscall_readonly!( |
459 | __NR_fcntl64, |
460 | fd, |
461 | c_uint(F_DUPFD_CLOEXEC), |
462 | raw_fd(min) |
463 | )) |
464 | } |
465 | #[cfg (target_pointer_width = "64" )] |
466 | unsafe { |
467 | ret_owned_fd(raw:syscall_readonly!( |
468 | __NR_fcntl, |
469 | fd, |
470 | c_uint(F_DUPFD_CLOEXEC), |
471 | raw_fd(min) |
472 | )) |
473 | } |
474 | } |
475 | |
476 | #[inline ] |
477 | pub(crate) fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> { |
478 | unsafe { |
479 | let mut result: MaybeUninit<[OwnedFd; 2]> = MaybeUninit::<[OwnedFd; 2]>::uninit(); |
480 | ret(raw:syscall!(__NR_pipe2, &mut result, flags))?; |
481 | let [p0: OwnedFd, p1: OwnedFd] = result.assume_init(); |
482 | Ok((p0, p1)) |
483 | } |
484 | } |
485 | |
486 | #[inline ] |
487 | pub(crate) fn pipe() -> io::Result<(OwnedFd, OwnedFd)> { |
488 | // aarch64 and risc64 omit `__NR_pipe`. On mips, `__NR_pipe` uses a special |
489 | // calling convention, but using it is not worth complicating our syscall |
490 | // wrapping infrastructure at this time. |
491 | #[cfg (any( |
492 | target_arch = "aarch64" , |
493 | target_arch = "mips" , |
494 | target_arch = "mips64" , |
495 | target_arch = "riscv64" , |
496 | ))] |
497 | { |
498 | pipe_with(PipeFlags::empty()) |
499 | } |
500 | #[cfg (not(any( |
501 | target_arch = "aarch64" , |
502 | target_arch = "mips" , |
503 | target_arch = "mips64" , |
504 | target_arch = "riscv64" , |
505 | )))] |
506 | unsafe { |
507 | let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); |
508 | ret(syscall!(__NR_pipe, &mut result))?; |
509 | let [p0, p1] = result.assume_init(); |
510 | Ok((p0, p1)) |
511 | } |
512 | } |
513 | |
514 | #[inline ] |
515 | pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> { |
516 | let (fds_addr_mut, fds_len) = slice_mut(fds); |
517 | |
518 | #[cfg (any(target_arch = "aarch64" , target_arch = "riscv64" ))] |
519 | unsafe { |
520 | let timeout = if timeout >= 0 { |
521 | Some(__kernel_timespec { |
522 | tv_sec: (timeout as i64) / 1000, |
523 | tv_nsec: (timeout as i64) % 1000 * 1_000_000, |
524 | }) |
525 | } else { |
526 | None |
527 | }; |
528 | ret_usize(syscall!( |
529 | __NR_ppoll, |
530 | fds_addr_mut, |
531 | fds_len, |
532 | opt_ref(timeout.as_ref()), |
533 | zero(), |
534 | size_of::<kernel_sigset_t, _>() |
535 | )) |
536 | } |
537 | #[cfg (not(any(target_arch = "aarch64" , target_arch = "riscv64" )))] |
538 | unsafe { |
539 | ret_usize(syscall!(__NR_poll, fds_addr_mut, fds_len, c_int(timeout))) |
540 | } |
541 | } |
542 | |
543 | #[inline ] |
544 | pub(crate) fn epoll_create(flags: epoll::CreateFlags) -> io::Result<OwnedFd> { |
545 | unsafe { ret_owned_fd(raw:syscall_readonly!(__NR_epoll_create1, flags)) } |
546 | } |
547 | |
548 | #[inline ] |
549 | pub(crate) unsafe fn epoll_add( |
550 | epfd: BorrowedFd<'_>, |
551 | fd: c::c_int, |
552 | event: &epoll_event, |
553 | ) -> io::Result<()> { |
554 | ret(raw:syscall_readonly!( |
555 | __NR_epoll_ctl, |
556 | epfd, |
557 | c_uint(EPOLL_CTL_ADD), |
558 | raw_fd(fd), |
559 | by_ref(event) |
560 | )) |
561 | } |
562 | |
563 | #[inline ] |
564 | pub(crate) unsafe fn epoll_mod( |
565 | epfd: BorrowedFd<'_>, |
566 | fd: c::c_int, |
567 | event: &epoll_event, |
568 | ) -> io::Result<()> { |
569 | ret(raw:syscall_readonly!( |
570 | __NR_epoll_ctl, |
571 | epfd, |
572 | c_uint(EPOLL_CTL_MOD), |
573 | raw_fd(fd), |
574 | by_ref(event) |
575 | )) |
576 | } |
577 | |
578 | #[inline ] |
579 | pub(crate) unsafe fn epoll_del(epfd: BorrowedFd<'_>, fd: c::c_int) -> io::Result<()> { |
580 | ret(raw:syscall_readonly!( |
581 | __NR_epoll_ctl, |
582 | epfd, |
583 | c_uint(EPOLL_CTL_DEL), |
584 | raw_fd(fd), |
585 | zero() |
586 | )) |
587 | } |
588 | |
589 | #[inline ] |
590 | pub(crate) fn epoll_wait( |
591 | epfd: BorrowedFd<'_>, |
592 | events: *mut epoll_event, |
593 | num_events: usize, |
594 | timeout: c::c_int, |
595 | ) -> io::Result<usize> { |
596 | #[cfg (not(any(target_arch = "aarch64" , target_arch = "riscv64" )))] |
597 | unsafe { |
598 | ret_usize(raw:syscall!( |
599 | __NR_epoll_wait, |
600 | epfd, |
601 | events, |
602 | pass_usize(num_events), |
603 | c_int(timeout) |
604 | )) |
605 | } |
606 | #[cfg (any(target_arch = "aarch64" , target_arch = "riscv64" ))] |
607 | unsafe { |
608 | ret_usize(syscall!( |
609 | __NR_epoll_pwait, |
610 | epfd, |
611 | events, |
612 | pass_usize(num_events), |
613 | c_int(timeout), |
614 | zero() |
615 | )) |
616 | } |
617 | } |
618 | |
619 | #[cfg (linux_kernel)] |
620 | #[inline ] |
621 | pub fn splice( |
622 | fd_in: BorrowedFd, |
623 | off_in: Option<&mut u64>, |
624 | fd_out: BorrowedFd, |
625 | off_out: Option<&mut u64>, |
626 | len: usize, |
627 | flags: SpliceFlags, |
628 | ) -> io::Result<usize> { |
629 | unsafe { |
630 | ret_usize(raw:syscall!( |
631 | __NR_splice, |
632 | fd_in, |
633 | opt_mut(off_in), |
634 | fd_out, |
635 | opt_mut(off_out), |
636 | pass_usize(len), |
637 | c_uint(flags.bits()) |
638 | )) |
639 | } |
640 | } |
641 | |
642 | #[cfg (linux_kernel)] |
643 | #[inline ] |
644 | pub unsafe fn vmsplice( |
645 | fd: BorrowedFd, |
646 | bufs: &[IoSliceRaw], |
647 | flags: SpliceFlags, |
648 | ) -> io::Result<usize> { |
649 | let (bufs_addr: ArgReg<'_, A1>, bufs_len: ArgReg<'_, A2>) = slice(&bufs[..cmp::min(v1:bufs.len(), v2:max_iov())]); |
650 | ret_usize(raw:syscall!( |
651 | __NR_vmsplice, |
652 | fd, |
653 | bufs_addr, |
654 | bufs_len, |
655 | c_uint(flags.bits()) |
656 | )) |
657 | } |
658 | |