Merge branch 'fix-ppoll' into 'master'

Handle signal mask in epoll_pwait

See merge request redox-os/relibc!879
This commit is contained in:
Jeremy Soller
2026-01-09 14:32:38 -07:00
3 changed files with 68 additions and 14 deletions
+29
View File
@@ -783,6 +783,34 @@ pub fn await_signal_async(inner_allowset: u64) -> Result<Unreachable> {
res?;
unreachable!()
}
/// Run a callback with the specified signal mask, atomically
pub fn callback_or_signal_async<T, F: FnOnce() -> Result<T>>(
inner_allowset: u64,
callback: F,
) -> Result<T> {
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,
+20 -6
View File
@@ -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(
+19 -8
View File
@@ -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<usize, Errno> {
// TODO: sigset
assert_eq!(mem::size_of::<epoll_event>(), mem::size_of::<Event>());
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::<syscall::Event>(),
)
})?;
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::<syscall::Event>(),
)
});
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::<syscall::Event>();
let mut count = 0;