From 219fdd4e2626f1d92edbba987fe434fbe6e79fcf Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Thu, 21 Dec 2023 17:24:56 +0800 Subject: [PATCH] [libos] Implement the rt_sigsuspend syscall --- src/libos/src/signal/do_sigsuspend.rs | 36 ++++++++++++++++++ src/libos/src/signal/do_sigtimedwait.rs | 50 ++++++++++++++++++++++++- src/libos/src/signal/mod.rs | 1 + src/libos/src/signal/syscalls.rs | 13 +++++++ src/libos/src/syscall/mod.rs | 6 +-- 5 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 src/libos/src/signal/do_sigsuspend.rs diff --git a/src/libos/src/signal/do_sigsuspend.rs b/src/libos/src/signal/do_sigsuspend.rs new file mode 100644 index 00000000..fc8cd3c1 --- /dev/null +++ b/src/libos/src/signal/do_sigsuspend.rs @@ -0,0 +1,36 @@ +use super::do_sigprocmask::do_rt_sigprocmask; +use super::do_sigtimedwait::PendingSigWaiter; +use super::{sigset_t, MaskOp, SigNum, SigSet, Signal}; +use crate::prelude::*; + +pub fn do_sigsuspend(mask: &sigset_t) -> Result<()> { + debug!("do_sigsuspend: mask: {:?}", mask); + + let thread = current!(); + let process = thread.process().clone(); + let mut original_sig_set = sigset_t::default(); + + // Set signal mask + let op_and_set = Some((MaskOp::SetMask, mask)); + do_rt_sigprocmask(op_and_set, Some(&mut original_sig_set))?; + + let interest = SigSet::from_c(!*mask); + let pending_sig_waiter = PendingSigWaiter::new(thread, process, interest); + + match pending_sig_waiter.suspend() { + Ok(_) => { + // Restore the original signal mask + let op_and_set = { + let op = MaskOp::SetMask; + let set = &original_sig_set; + Some((op, set)) + }; + do_rt_sigprocmask(op_and_set, None).unwrap(); + Err(errno!(EINTR, "Wait for EINTR signal successfully")) + } + Err(_) => { + // Impossible path + Err(errno!(EFAULT, "No interesting, pending signal")) + } + } +} diff --git a/src/libos/src/signal/do_sigtimedwait.rs b/src/libos/src/signal/do_sigtimedwait.rs index 72b85930..c2dda831 100644 --- a/src/libos/src/signal/do_sigtimedwait.rs +++ b/src/libos/src/signal/do_sigtimedwait.rs @@ -35,7 +35,7 @@ pub fn do_sigtimedwait(interest: SigSet, timeout: Option<&Duration>) -> Result Result<()> { + let waiter_queue = self.observer.waiter_queue(); + let waiter = Waiter::new(); + // As EINTR may occur even if there are no interesting signals + loop { + // Try to search for an interesting signal from the current process or thread + if has_interest_signal(&self.interest, &self.thread, &self.process) { + return Ok(()); + } + + // Enqueue the waiter so that it can be waken up by the queue later. + waiter_queue.reset_and_enqueue(&waiter); + + // As there is no intersting signal right now, let's wait for + // the arrival of an interesting signal. + let res = waiter.wait(None); + + // Do not try again if some error is encountered. There are only + // two possible errors: ETIMEDOUT or EINTR. + if let Err(e) = res { + // When interrupted is reached, it is possible that the interrupting signal happens + // to be an interesting and pending signal. So we attempt to search for signals again. + if e.errno() == Errno::EINTR { + if has_interest_signal(&self.interest, &self.thread, &self.process) { + return Ok(()); + } + } else { + // Impossible case + return Err(e); + } + } + } + } } impl Drop for PendingSigWaiter { @@ -129,6 +163,20 @@ impl Drop for PendingSigWaiter { } } +fn has_interest_signal(interest: &SigSet, thread: &ThreadRef, process: &ProcessRef) -> bool { + let blocked = !*interest; + process + .sig_queues() + .write() + .unwrap() + .has_valid_signal(&blocked) + || thread + .sig_queues() + .write() + .unwrap() + .has_valid_signal(&blocked) +} + fn dequeue_pending_signal( interest: &SigSet, thread: &ThreadRef, diff --git a/src/libos/src/signal/mod.rs b/src/libos/src/signal/mod.rs index c2cbe448..13b84124 100644 --- a/src/libos/src/signal/mod.rs +++ b/src/libos/src/signal/mod.rs @@ -23,6 +23,7 @@ mod do_sigaction; mod do_sigaltstack; mod do_sigpending; mod do_sigreturn; +mod do_sigsuspend; mod do_sigtimedwait; mod sig_action; mod sig_dispositions; diff --git a/src/libos/src/signal/syscalls.rs b/src/libos/src/signal/syscalls.rs index e43b7d10..411a9177 100644 --- a/src/libos/src/signal/syscalls.rs +++ b/src/libos/src/signal/syscalls.rs @@ -194,3 +194,16 @@ pub fn do_rt_sigtimedwait( *info = super::do_sigtimedwait::do_sigtimedwait(mask, timeout.as_ref())?; Ok(0) } + +pub fn do_rt_sigsuspend(mask_ptr: *const sigset_t) -> Result { + let mask = { + if mask_ptr.is_null() { + return_errno!(EFAULT, "ptr must not be null"); + } + from_user::check_ptr(mask_ptr)?; + unsafe { *mask_ptr } + }; + + super::do_sigsuspend::do_sigsuspend(&mask)?; + Ok(0) +} diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 32190de8..6b17c0aa 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -60,8 +60,8 @@ use crate::sched::{ }; use crate::signal::{ do_kill, do_rt_sigaction, do_rt_sigpending, do_rt_sigprocmask, do_rt_sigreturn, - do_rt_sigtimedwait, do_sigaltstack, do_tgkill, do_tkill, sigaction_t, siginfo_t, sigset_t, - stack_t, + do_rt_sigsuspend, do_rt_sigtimedwait, do_sigaltstack, do_tgkill, do_tkill, sigaction_t, + siginfo_t, sigset_t, stack_t, }; use crate::vm::{MMapFlags, MRemapFlags, MSyncFlags, MadviceFlags, VMPerms}; use crate::{fs, process, std, vm}; @@ -227,7 +227,7 @@ macro_rules! process_syscall_table_with_callback { (RtSigpending = 127) => do_rt_sigpending(buf_ptr: *mut sigset_t, buf_size: usize), (RtSigtimedwait = 128) => do_rt_sigtimedwait(mask_ptr: *const sigset_t, info_ptr: *mut siginfo_t, timeout_ptr: *const timespec_t, mask_size: usize), (RtSigqueueinfo = 129) => handle_unsupported(), - (RtSigsuspend = 130) => handle_unsupported(), + (RtSigsuspend = 130) => do_rt_sigsuspend(mask_ptr: *const sigset_t), (Sigaltstack = 131) => do_sigaltstack(ss: *const stack_t, old_ss: *mut stack_t, context: *const CpuContext), (Utime = 132) => do_utime(path: *const i8, times: *const utimbuf_t), (Mknod = 133) => handle_unsupported(),