55//! See the `rustix::backend` module documentation for details.
66#![ allow( unsafe_code, clippy:: undocumented_unsafe_blocks) ]
77
8- #[ cfg( feature = "alloc" ) ]
9- use crate :: backend:: c;
108use crate :: backend:: conv:: {
119 by_ref, c_int, c_uint, opt_ref, ret, ret_c_int, ret_error, ret_owned_fd, ret_usize, size_of,
1210 slice_mut, zero,
1311} ;
1412use crate :: event:: { epoll, EventfdFlags , FdSetElement , PollFd , Timespec } ;
1513use crate :: fd:: { BorrowedFd , OwnedFd } ;
1614use crate :: io;
17- use crate :: utils:: { as_mut_ptr, option_as_ptr} ;
15+ use crate :: utils:: as_mut_ptr;
16+ #[ cfg( feature = "linux_5_11" ) ]
17+ use crate :: utils:: option_as_ptr;
1818#[ cfg( feature = "alloc" ) ]
1919use core:: mem:: MaybeUninit ;
2020use core:: ptr:: null_mut;
@@ -24,14 +24,12 @@ use linux_raw_sys::general::{kernel_sigset_t, EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOL
2424pub ( crate ) fn poll ( fds : & mut [ PollFd < ' _ > ] , timeout : Option < & Timespec > ) -> io:: Result < usize > {
2525 let ( fds_addr_mut, fds_len) = slice_mut ( fds) ;
2626
27- let timeout = option_as_ptr ( timeout) ;
28-
2927 unsafe {
3028 ret_usize ( syscall ! (
3129 __NR_ppoll,
3230 fds_addr_mut,
3331 fds_len,
34- opt_ref( timeout. as_ref ( ) ) ,
32+ opt_ref( timeout) ,
3533 zero( ) ,
3634 size_of:: <kernel_sigset_t, _>( )
3735 ) )
@@ -181,33 +179,53 @@ pub(crate) fn epoll_del(epfd: BorrowedFd<'_>, fd: BorrowedFd<'_>) -> io::Result<
181179pub ( crate ) fn epoll_wait (
182180 epfd : BorrowedFd < ' _ > ,
183181 events : & mut [ MaybeUninit < crate :: event:: epoll:: Event > ] ,
184- timeout : c :: c_int ,
182+ timeout : Option < & Timespec > ,
185183) -> io:: Result < usize > {
186184 let ( buf_addr_mut, buf_len) = slice_mut ( events) ;
187- // SAFETY: `__NR_epoll_wait` doesn't access any user memory outside of
188- // the `events` array.
189- #[ cfg( not( any( target_arch = "aarch64" , target_arch = "riscv64" ) ) ) ]
190- unsafe {
191- ret_usize ( syscall ! (
192- __NR_epoll_wait,
193- epfd,
194- buf_addr_mut,
195- buf_len,
196- c_int( timeout)
197- ) )
185+
186+ // If we have Linux 5.11, use `epoll_pwait2`, which takes a `timespec`.
187+ #[ cfg( feature = "linux_5_11" ) ]
188+ {
189+ let timeout = option_as_ptr ( timeout) ;
190+
191+ // SAFETY: `__NR_epoll_pwait2` doesn't access any user memory outside of
192+ // the `events` array, as we don't pass it a `sigmask`.
193+ unsafe {
194+ ret_usize ( syscall ! (
195+ __NR_epoll_pwait2,
196+ epfd,
197+ buf_addr_mut,
198+ buf_len,
199+ timeout,
200+ zero( )
201+ ) )
202+ }
198203 }
199- // SAFETY: `__NR_epoll_pwait` doesn't access any user memory outside of
200- // the `events` array, as we don't pass it a `sigmask`.
201- #[ cfg( any( target_arch = "aarch64" , target_arch = "riscv64" ) ) ]
202- unsafe {
203- ret_usize ( syscall ! (
204- __NR_epoll_pwait,
205- epfd,
206- buf_addr_mut,
207- buf_len,
208- c_int( timeout) ,
209- zero( )
210- ) )
204+
205+ // If we don't have Linux 5.11, use `epoll_pwait`, which takes a `c_int`.
206+ //
207+ // We do this unconditionally, rather than trying `epoll_pwait2` and
208+ // falling back on `Errno::NOSYS`, because seccomp configurations will
209+ // sometimes abort the process on syscalls they don't recognize.
210+ #[ cfg( not( feature = "linux_5_11" ) ) ]
211+ {
212+ let timeout = match timeout {
213+ None => -1 ,
214+ Some ( timeout) => timeout. as_c_int_millis ( ) . ok_or ( io:: Errno :: INVAL ) ?,
215+ } ;
216+
217+ // SAFETY: `__NR_epoll_pwait` doesn't access any user memory outside of
218+ // the `events` array, as we don't pass it a `sigmask`.
219+ unsafe {
220+ ret_usize ( syscall ! (
221+ __NR_epoll_pwait,
222+ epfd,
223+ buf_addr_mut,
224+ buf_len,
225+ c_int( timeout) ,
226+ zero( )
227+ ) )
228+ }
211229 }
212230}
213231
0 commit comments