[libos] Implement the rt_sigsuspend syscall

This commit is contained in:
ClawSeven 2023-12-21 17:24:56 +08:00 committed by volcano
parent d6741c0096
commit 219fdd4e26
5 changed files with 102 additions and 4 deletions

@ -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"))
}
}
}

@ -35,7 +35,7 @@ pub fn do_sigtimedwait(interest: SigSet, timeout: Option<&Duration>) -> Result<s
Ok(siginfo) Ok(siginfo)
} }
struct PendingSigWaiter { pub struct PendingSigWaiter {
thread: ThreadRef, thread: ThreadRef,
process: ProcessRef, process: ProcessRef,
interest: SigSet, interest: SigSet,
@ -109,6 +109,40 @@ impl PendingSigWaiter {
} }
} }
} }
pub fn suspend(&self) -> 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 { 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( fn dequeue_pending_signal(
interest: &SigSet, interest: &SigSet,
thread: &ThreadRef, thread: &ThreadRef,

@ -23,6 +23,7 @@ mod do_sigaction;
mod do_sigaltstack; mod do_sigaltstack;
mod do_sigpending; mod do_sigpending;
mod do_sigreturn; mod do_sigreturn;
mod do_sigsuspend;
mod do_sigtimedwait; mod do_sigtimedwait;
mod sig_action; mod sig_action;
mod sig_dispositions; mod sig_dispositions;

@ -194,3 +194,16 @@ pub fn do_rt_sigtimedwait(
*info = super::do_sigtimedwait::do_sigtimedwait(mask, timeout.as_ref())?; *info = super::do_sigtimedwait::do_sigtimedwait(mask, timeout.as_ref())?;
Ok(0) Ok(0)
} }
pub fn do_rt_sigsuspend(mask_ptr: *const sigset_t) -> Result<isize> {
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)
}

@ -60,8 +60,8 @@ use crate::sched::{
}; };
use crate::signal::{ use crate::signal::{
do_kill, do_rt_sigaction, do_rt_sigpending, do_rt_sigprocmask, do_rt_sigreturn, 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, do_rt_sigsuspend, do_rt_sigtimedwait, do_sigaltstack, do_tgkill, do_tkill, sigaction_t,
stack_t, siginfo_t, sigset_t, stack_t,
}; };
use crate::vm::{MMapFlags, MRemapFlags, MSyncFlags, MadviceFlags, VMPerms}; use crate::vm::{MMapFlags, MRemapFlags, MSyncFlags, MadviceFlags, VMPerms};
use crate::{fs, process, std, vm}; 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), (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), (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(), (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), (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), (Utime = 132) => do_utime(path: *const i8, times: *const utimbuf_t),
(Mknod = 133) => handle_unsupported(), (Mknod = 133) => handle_unsupported(),