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:
		
							parent
							
								
									cfda47b316
								
							
						
					
					
						commit
						0db804d131
					
				@ -8,12 +8,12 @@ use crate::syscall::CpuContext;
 | 
			
		||||
 | 
			
		||||
pub fn do_rt_sigreturn(curr_user_ctxt: &mut CpuContext) -> Result<()> {
 | 
			
		||||
    debug!("do_rt_sigreturn");
 | 
			
		||||
    let last_user_ctxt = {
 | 
			
		||||
        let last_user_ctxt = PRE_USER_CONTEXTS.with(|ref_cell| {
 | 
			
		||||
    let last_ucontext = {
 | 
			
		||||
        let last_ucontext = PRE_UCONTEXTS.with(|ref_cell| {
 | 
			
		||||
            let mut stack = ref_cell.borrow_mut();
 | 
			
		||||
            stack.pop()
 | 
			
		||||
        });
 | 
			
		||||
        if last_user_ctxt.is_none() {
 | 
			
		||||
        if last_ucontext.is_none() {
 | 
			
		||||
            let term_status = TermStatus::Killed(SIGKILL);
 | 
			
		||||
            current!().process().force_exit(term_status);
 | 
			
		||||
            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"
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        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(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -109,7 +112,7 @@ fn handle_signal(
 | 
			
		||||
    process: &ProcessRef,
 | 
			
		||||
    cpu_context: &mut CpuContext,
 | 
			
		||||
) -> 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();
 | 
			
		||||
        stack.full()
 | 
			
		||||
    });
 | 
			
		||||
@ -152,6 +155,7 @@ fn handle_signal(
 | 
			
		||||
        } => {
 | 
			
		||||
            let ret = handle_signals_by_user(
 | 
			
		||||
                signal,
 | 
			
		||||
                thread,
 | 
			
		||||
                handler_addr,
 | 
			
		||||
                flags,
 | 
			
		||||
                restorer_addr,
 | 
			
		||||
@ -169,12 +173,24 @@ fn handle_signal(
 | 
			
		||||
 | 
			
		||||
fn handle_signals_by_user(
 | 
			
		||||
    signal: Box<dyn Signal>,
 | 
			
		||||
    thread: &ThreadRef,
 | 
			
		||||
    handler_addr: usize,
 | 
			
		||||
    flags: SigActionFlags,
 | 
			
		||||
    restorer_addr: usize,
 | 
			
		||||
    mask: SigSet,
 | 
			
		||||
    new_sigmask: SigSet,
 | 
			
		||||
    curr_user_ctxt: &mut CpuContext,
 | 
			
		||||
) -> 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
 | 
			
		||||
    let mut user_stack = {
 | 
			
		||||
        let get_stack_top = || -> usize {
 | 
			
		||||
@ -218,22 +234,18 @@ fn handle_signals_by_user(
 | 
			
		||||
        let ucontext = user_stack.alloc_aligned::<ucontext_t>(16)?;
 | 
			
		||||
        // TODO: set all fields in ucontext
 | 
			
		||||
        *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
 | 
			
		||||
    };
 | 
			
		||||
    // 3. Save the current user CPU context on the stack of 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
 | 
			
		||||
    // 3. Set up the call return address on the stack before we "call" the signal handler
 | 
			
		||||
    let handler_stack_top = {
 | 
			
		||||
        let handler_stack_top = user_stack.alloc::<usize>()?;
 | 
			
		||||
        *handler_stack_top = restorer_addr;
 | 
			
		||||
        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
 | 
			
		||||
    // 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.rdx = ucontext as u64;
 | 
			
		||||
 | 
			
		||||
    PRE_USER_CONTEXTS.with(|ref_cell| {
 | 
			
		||||
    PRE_UCONTEXTS.with(|ref_cell| {
 | 
			
		||||
        let mut stack = ref_cell.borrow_mut();
 | 
			
		||||
        stack.push(saved_user_ctxt).unwrap();
 | 
			
		||||
        stack.push(ucontext).unwrap();
 | 
			
		||||
    });
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
@ -322,12 +334,12 @@ impl Stack {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
thread_local! {
 | 
			
		||||
    static PRE_USER_CONTEXTS: RefCell<CpuContextStack> = Default::default();
 | 
			
		||||
    static PRE_UCONTEXTS: RefCell<CpuContextStack> = Default::default();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Default)]
 | 
			
		||||
struct CpuContextStack {
 | 
			
		||||
    stack: [Option<*mut CpuContext>; 32],
 | 
			
		||||
    stack: [Option<*mut ucontext_t>; 32],
 | 
			
		||||
    count: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -344,7 +356,7 @@ impl CpuContextStack {
 | 
			
		||||
        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() {
 | 
			
		||||
            return_errno!(ENOMEM, "cpu context stack is full");
 | 
			
		||||
        }
 | 
			
		||||
@ -353,7 +365,7 @@ impl CpuContextStack {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn pop(&mut self) -> Option<*mut CpuContext> {
 | 
			
		||||
    pub fn pop(&mut self) -> Option<*mut ucontext_t> {
 | 
			
		||||
        if self.empty() {
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user