From 971462ed8ad930b59822de9384787cf8d45f64b2 Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Tue, 12 May 2026 09:58:52 -0700 Subject: [PATCH] implement exceptfds partially for sys_pselect6 to fix arch bash and sh. --- src/process/fd_table/select.rs | 157 ++++++++++++++++++++++++--------- 1 file changed, 114 insertions(+), 43 deletions(-) diff --git a/src/process/fd_table/select.rs b/src/process/fd_table/select.rs index e5758e3..580e87b 100644 --- a/src/process/fd_table/select.rs +++ b/src/process/fd_table/select.rs @@ -24,8 +24,8 @@ pub struct FdSet { } impl FdSet { - fn iter_fds(&self, max: i32) -> impl Iterator { - let mut candidate_fd = 0; + fn iter_fds(&self, max: usize) -> impl Iterator { + let mut candidate_fd = 0usize; iter::from_fn(move || { loop { @@ -33,8 +33,8 @@ impl FdSet { return None; } - if self.set[candidate_fd as usize / 64] & (1 << (candidate_fd % 64)) != 0 { - let ret = Fd(candidate_fd); + if self.set[candidate_fd / 64] & (1 << (candidate_fd % 64)) != 0 { + let ret = Fd(candidate_fd as i32); candidate_fd += 1; return Some(ret); @@ -58,26 +58,54 @@ impl FdSet { unsafe impl UserCopyable for FdSet {} -// TODO: handle exceptfds +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub(crate) struct PSelect6SigMask { + sigmask: TUA, + sigsetsize: usize, +} + +unsafe impl UserCopyable for PSelect6SigMask {} + +// TODO: handle exceptfds readiness semantics. pub async fn sys_pselect6( ctx: &ProcessCtx, max: i32, readfds: TUA, writefds: TUA, - _exceptfds: TUA, + exceptfds: TUA, timeout: TUA, - mask: TUA, + mask: TUA, ) -> Result { + if max < 0 || max as usize > SET_SIZE { + return Err(KernelError::InvalidValue); + } + + let max = max as usize; let task = ctx.shared(); - let mut read_fd_set = copy_from_user(readfds).await?; + let mut read_fd_set = if readfds.is_null() { + None + } else { + Some(copy_from_user(readfds).await?) + }; let mut read_fds = Vec::new(); - let mut write_fd_set = copy_from_user(writefds).await?; + let mut write_fd_set = if writefds.is_null() { + None + } else { + Some(copy_from_user(writefds).await?) + }; let mut write_fds = Vec::new(); + let mut except_fd_set = if exceptfds.is_null() { + None + } else { + Some(copy_from_user(exceptfds).await?) + }; + let mut timeout_fut = if timeout.is_null() { None } else { @@ -85,44 +113,58 @@ pub async fn sys_pselect6( Some(pin!(sleep(duration))) }; - for fd in read_fd_set.iter_fds(max) { - let file = task - .fd_table - .lock_save_irq() - .get(fd) - .ok_or(KernelError::BadFd)?; + if let Some(ref read_fd_set) = read_fd_set { + for fd in read_fd_set.iter_fds(max) { + let file = task + .fd_table + .lock_save_irq() + .get(fd) + .ok_or(KernelError::BadFd)?; - read_fds.push(( - Box::pin(async move { - let (ops, _) = &mut *file.lock().await; + read_fds.push(( + Box::pin(async move { + let (ops, _) = &mut *file.lock().await; - ops.poll_read_ready().await - }), - fd, - )); + ops.poll_read_ready().await + }), + fd, + )); + } } - for fd in write_fd_set.iter_fds(max) { - let file = task - .fd_table - .lock_save_irq() - .get(fd) - .ok_or(KernelError::BadFd)?; + if let Some(ref write_fd_set) = write_fd_set { + for fd in write_fd_set.iter_fds(max) { + let file = task + .fd_table + .lock_save_irq() + .get(fd) + .ok_or(KernelError::BadFd)?; - write_fds.push(( - Box::pin(async move { - let (ops, _) = &mut *file.lock().await; + write_fds.push(( + Box::pin(async move { + let (ops, _) = &mut *file.lock().await; - ops.poll_write_ready().await - }), - fd, - )); + ops.poll_write_ready().await + }), + fd, + )); + } } let mask = if mask.is_null() { None } else { - Some(copy_from_user(mask).await?) + let args: PSelect6SigMask = copy_from_user(mask).await?; + + if args.sigsetsize != core::mem::size_of::() { + return Err(KernelError::InvalidValue); + } + + if args.sigmask.is_null() { + None + } else { + Some(copy_from_user(args.sigmask).await?) + } }; let old_sigmask = task.sig_mask.load(); if let Some(mask) = mask { @@ -131,8 +173,15 @@ pub async fn sys_pselect6( task.sig_mask.store(new_sigmask); } - read_fd_set.zero(); - write_fd_set.zero(); + if let Some(ref mut read_fd_set) = read_fd_set { + read_fd_set.zero(); + } + if let Some(ref mut write_fd_set) = write_fd_set { + write_fd_set.zero(); + } + if let Some(ref mut except_fd_set) = except_fd_set { + except_fd_set.zero(); + } let n = poll_fn(|cx| { let mut num_ready: usize = 0; @@ -140,15 +189,19 @@ pub async fn sys_pselect6( for (fut, fd) in read_fds.iter_mut() { if fut.as_mut().poll(cx).is_ready() { // Mark the is_ready bool. Don't break out of the loop just - // yet, we may aswell check all fds while we're here. - read_fd_set.set_fd(*fd); + // yet, we may as well check all fds while we're here. + if let Some(ref mut read_fd_set) = read_fd_set { + read_fd_set.set_fd(*fd); + } num_ready += 1; } } for (fut, fd) in write_fds.iter_mut() { if fut.as_mut().poll(cx).is_ready() { - write_fd_set.set_fd(*fd); + if let Some(ref mut write_fd_set) = write_fd_set { + write_fd_set.set_fd(*fd); + } num_ready += 1; } } @@ -166,12 +219,30 @@ pub async fn sys_pselect6( }) .await; - copy_to_user(readfds, read_fd_set).await?; - copy_to_user(writefds, write_fd_set).await?; + let readfds_copy_result = if let Some(read_fd_set) = read_fd_set { + copy_to_user(readfds, read_fd_set).await + } else { + Ok(()) + }; + let writefds_copy_result = if let Some(write_fd_set) = write_fd_set { + copy_to_user(writefds, write_fd_set).await + } else { + Ok(()) + }; + let exceptfds_copy_result = if let Some(except_fd_set) = except_fd_set { + copy_to_user(exceptfds, except_fd_set).await + } else { + Ok(()) + }; + if mask.is_some() { task.sig_mask.store(old_sigmask); } + readfds_copy_result?; + writefds_copy_result?; + exceptfds_copy_result?; + Ok(n) }