[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)
|
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(),
|
||||||
|
Loading…
Reference in New Issue
Block a user