[libos] Implement the rt_sigsuspend syscall
This commit is contained in:
parent
d6741c0096
commit
219fdd4e26
36
src/libos/src/signal/do_sigsuspend.rs
Normal file
36
src/libos/src/signal/do_sigsuspend.rs
Normal file
@ -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)
|
||||
}
|
||||
|
||||
struct PendingSigWaiter {
|
||||
pub struct PendingSigWaiter {
|
||||
thread: ThreadRef,
|
||||
process: ProcessRef,
|
||||
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 {
|
||||
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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<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::{
|
||||
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(),
|
||||
|
Loading…
Reference in New Issue
Block a user