diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 026ba119b8..177dcca416 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -783,6 +783,34 @@ pub fn await_signal_async(inner_allowset: u64) -> Result { res?; unreachable!() } + +/// Run a callback with the specified signal mask, atomically +pub fn callback_or_signal_async Result>( + inner_allowset: u64, + callback: F, +) -> Result { + let _guard = tmp_disable_signals(); + let control = &unsafe { Tcb::current().unwrap() }.os_specific.control; + + let old_allowset = get_allowset_raw(&control.word); + set_allowset_raw(&control.word, old_allowset, inner_allowset); + let res = callback(); + if let Err(err) = &res { + if err.errno == EINTR { + // Run trampoline if EINTR returned + unsafe { + manually_enter_trampoline(); + } + } + } + + // POSIX says it shall restore the mask to what it was prior to the call, which is interpreted + // as allowing any changes to sigprocmask inside the signal handler, to be discarded. + set_allowset_raw(&control.word, inner_allowset, old_allowset); + + res +} + /*#[unsafe(no_mangle)] pub extern "C" fn __redox_rt_debug_sigctl() { let tcb = &RtTcb::current().control; @@ -830,6 +858,7 @@ pub fn await_signal_sync(inner_allowset: u64, timeout: Option<&TimeSpec>) -> Res // Normally ETIMEDOUT but not for sigtimedwait. .ok_or(Error::new(EAGAIN)) } + fn try_claim_multiple( mut proc_pending: u64, mut thread_pending: u64, diff --git a/src/header/poll/mod.rs b/src/header/poll/mod.rs index 8c8cbd22b0..5f4326c293 100644 --- a/src/header/poll/mod.rs +++ b/src/header/poll/mod.rs @@ -11,6 +11,7 @@ use crate::{ error::ResultExt, fs::File, header::{ + errno::EBADF, signal::sigset_t, sys_epoll::{ EPOLL_CLOEXEC, EPOLL_CTL_ADD, EPOLLERR, EPOLLHUP, EPOLLIN, EPOLLNVAL, EPOLLOUT, @@ -19,7 +20,10 @@ use crate::{ }, time::timespec, }, - platform::types::{c_int, c_short, c_ulong}, + platform::{ + self, + types::{c_int, c_short, c_ulong}, + }, }; pub const POLLIN: c_short = 0x001; @@ -65,12 +69,14 @@ pub fn poll_epoll(fds: &mut [pollfd], timeout: c_int, sigmask: *const sigset_t) File::new(epfd) }; + let mut closed = 0; for i in 0..fds.len() { let mut pfd = &mut fds[i]; - // Ignore the entry with negative fd, set the revents to 0 + pfd.revents = 0; + + // Ignore the entry with negative fd if pfd.fd < 0 { - pfd.revents = 0; continue; } @@ -86,13 +92,21 @@ pub fn poll_epoll(fds: &mut [pollfd], timeout: c_int, sigmask: *const sigset_t) } } - pfd.revents = 0; - if unsafe { epoll_ctl(*ep, EPOLL_CTL_ADD, pfd.fd, &mut event) } < 0 { - return -1; + if platform::ERRNO.get() == EBADF { + pfd.revents |= POLLNVAL; + closed += 1; + } else { + return -1; + } } } + // Early exit if there are fds, and all are closed (revents = POLLNVAL) + if closed > 0 && closed == fds.len() { + return closed as i32; + } + let mut events: [epoll_event; 32] = unsafe { mem::zeroed() }; let res = unsafe { epoll_pwait( diff --git a/src/platform/redox/epoll.rs b/src/platform/redox/epoll.rs index 14e8a6853f..fe3166222b 100644 --- a/src/platform/redox/epoll.rs +++ b/src/platform/redox/epoll.rs @@ -96,9 +96,8 @@ impl PalEpoll for Sys { events: *mut epoll_event, maxevents: c_int, timeout: c_int, - _sigset: *const sigset_t, + sigset: *const sigset_t, ) -> Result { - // TODO: sigset assert_eq!(mem::size_of::(), mem::size_of::()); if maxevents <= 0 { @@ -131,12 +130,24 @@ impl PalEpoll for Sys { None }; - let bytes_read = Sys::read(epfd, unsafe { - slice::from_raw_parts_mut( - events as *mut u8, - maxevents as usize * mem::size_of::(), - ) - })?; + let callback = || { + let res = syscall::read(epfd as usize, unsafe { + slice::from_raw_parts_mut( + events as *mut u8, + maxevents as usize * mem::size_of::(), + ) + }); + res + }; + + let bytes_read = if sigset.is_null() { + callback() + } else { + // Allowset is inverse of sigset mask + let allowset = !*sigset; + redox_rt::signal::callback_or_signal_async(allowset, callback) + }?; + let read = bytes_read as usize / mem::size_of::(); let mut count = 0;