Support sa_mask for sigaction syscall

Struct sigaction has a field named sa_mask, which specifies the blocked
signals while executing the signal handler. Previously, this field is not
supported. This commit adds this missing feature.
This commit is contained in:
Tate, Hongliang Tian 2020-07-13 17:32:30 +08:00 committed by zongmin.gzm
parent cfda47b316
commit 0db804d131

@ -8,12 +8,12 @@ use crate::syscall::CpuContext;
pub fn do_rt_sigreturn(curr_user_ctxt: &mut CpuContext) -> Result<()> { pub fn do_rt_sigreturn(curr_user_ctxt: &mut CpuContext) -> Result<()> {
debug!("do_rt_sigreturn"); debug!("do_rt_sigreturn");
let last_user_ctxt = { let last_ucontext = {
let last_user_ctxt = PRE_USER_CONTEXTS.with(|ref_cell| { let last_ucontext = PRE_UCONTEXTS.with(|ref_cell| {
let mut stack = ref_cell.borrow_mut(); let mut stack = ref_cell.borrow_mut();
stack.pop() stack.pop()
}); });
if last_user_ctxt.is_none() { if last_ucontext.is_none() {
let term_status = TermStatus::Killed(SIGKILL); let term_status = TermStatus::Killed(SIGKILL);
current!().process().force_exit(term_status); current!().process().force_exit(term_status);
return_errno!( return_errno!(
@ -21,9 +21,12 @@ pub fn do_rt_sigreturn(curr_user_ctxt: &mut CpuContext) -> Result<()> {
"sigreturn should not have been called; kill this process" "sigreturn should not have been called; kill this process"
); );
} }
unsafe { &*last_user_ctxt.unwrap() } unsafe { &*last_ucontext.unwrap() }
}; };
*curr_user_ctxt = *last_user_ctxt; // Restore sigmask
*current!().sig_mask().write().unwrap() = SigSet::from_c(last_ucontext.uc_sigmask);
// Restore user context
*curr_user_ctxt = last_ucontext.uc_mcontext.inner;
Ok(()) Ok(())
} }
@ -109,7 +112,7 @@ fn handle_signal(
process: &ProcessRef, process: &ProcessRef,
cpu_context: &mut CpuContext, cpu_context: &mut CpuContext,
) -> bool { ) -> bool {
let is_sig_stack_full = PRE_USER_CONTEXTS.with(|ref_cell| { let is_sig_stack_full = PRE_UCONTEXTS.with(|ref_cell| {
let stack = ref_cell.borrow(); let stack = ref_cell.borrow();
stack.full() stack.full()
}); });
@ -152,6 +155,7 @@ fn handle_signal(
} => { } => {
let ret = handle_signals_by_user( let ret = handle_signals_by_user(
signal, signal,
thread,
handler_addr, handler_addr,
flags, flags,
restorer_addr, restorer_addr,
@ -169,12 +173,24 @@ fn handle_signal(
fn handle_signals_by_user( fn handle_signals_by_user(
signal: Box<dyn Signal>, signal: Box<dyn Signal>,
thread: &ThreadRef,
handler_addr: usize, handler_addr: usize,
flags: SigActionFlags, flags: SigActionFlags,
restorer_addr: usize, restorer_addr: usize,
mask: SigSet, new_sigmask: SigSet,
curr_user_ctxt: &mut CpuContext, curr_user_ctxt: &mut CpuContext,
) -> Result<()> { ) -> Result<()> {
let old_sigmask = {
let mut sigmask = thread.sig_mask().write().unwrap();
let old_sigmask = *sigmask;
*sigmask = new_sigmask;
if !flags.contains(SigActionFlags::SA_NODEFER) {
// Block the current signal while executing the signal handler
*sigmask += signal.num();
}
old_sigmask
};
// Represent the user stack in a memory safe way // Represent the user stack in a memory safe way
let mut user_stack = { let mut user_stack = {
let get_stack_top = || -> usize { let get_stack_top = || -> usize {
@ -218,22 +234,18 @@ fn handle_signals_by_user(
let ucontext = user_stack.alloc_aligned::<ucontext_t>(16)?; let ucontext = user_stack.alloc_aligned::<ucontext_t>(16)?;
// TODO: set all fields in ucontext // TODO: set all fields in ucontext
*ucontext = unsafe { std::mem::zeroed() }; *ucontext = unsafe { std::mem::zeroed() };
// Save the old sigmask
ucontext.uc_sigmask = old_sigmask.to_c();
// Save the user context
ucontext.uc_mcontext.inner = *curr_user_ctxt;
ucontext as *mut ucontext_t ucontext as *mut ucontext_t
}; };
// 3. Save the current user CPU context on the stack of the signal handler // 3. Set up the call return address on the stack before we "call" the signal handler
// so that we can restore the CPU context upon `sigreturn` syscall.
let saved_user_ctxt = {
let saved_user_ctxt = unsafe { &mut (*ucontext).uc_mcontext.inner };
*saved_user_ctxt = *curr_user_ctxt;
saved_user_ctxt as *mut CpuContext
};
// 4. Set up the call return address on the stack before we "call" the signal handler
let handler_stack_top = { let handler_stack_top = {
let handler_stack_top = user_stack.alloc::<usize>()?; let handler_stack_top = user_stack.alloc::<usize>()?;
*handler_stack_top = restorer_addr; *handler_stack_top = restorer_addr;
handler_stack_top as *mut usize handler_stack_top as *mut usize
}; };
// TODO: mask signals while the signal handler is executing
// Modify the current user CPU context so that the signal handler will // Modify the current user CPU context so that the signal handler will
// be "called" upon returning back to the user space and when the signal // be "called" upon returning back to the user space and when the signal
@ -245,9 +257,9 @@ fn handle_signals_by_user(
curr_user_ctxt.rsi = info as u64; curr_user_ctxt.rsi = info as u64;
curr_user_ctxt.rdx = ucontext as u64; curr_user_ctxt.rdx = ucontext as u64;
PRE_USER_CONTEXTS.with(|ref_cell| { PRE_UCONTEXTS.with(|ref_cell| {
let mut stack = ref_cell.borrow_mut(); let mut stack = ref_cell.borrow_mut();
stack.push(saved_user_ctxt).unwrap(); stack.push(ucontext).unwrap();
}); });
Ok(()) Ok(())
} }
@ -322,12 +334,12 @@ impl Stack {
} }
thread_local! { thread_local! {
static PRE_USER_CONTEXTS: RefCell<CpuContextStack> = Default::default(); static PRE_UCONTEXTS: RefCell<CpuContextStack> = Default::default();
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct CpuContextStack { struct CpuContextStack {
stack: [Option<*mut CpuContext>; 32], stack: [Option<*mut ucontext_t>; 32],
count: usize, count: usize,
} }
@ -344,7 +356,7 @@ impl CpuContextStack {
self.count == 0 self.count == 0
} }
pub fn push(&mut self, cpu_context: *mut CpuContext) -> Result<()> { pub fn push(&mut self, cpu_context: *mut ucontext_t) -> Result<()> {
if self.full() { if self.full() {
return_errno!(ENOMEM, "cpu context stack is full"); return_errno!(ENOMEM, "cpu context stack is full");
} }
@ -353,7 +365,7 @@ impl CpuContextStack {
Ok(()) Ok(())
} }
pub fn pop(&mut self) -> Option<*mut CpuContext> { pub fn pop(&mut self) -> Option<*mut ucontext_t> {
if self.empty() { if self.empty() {
return None; return None;
} }