diff options
Diffstat (limited to 'kernel/signal.c')
| -rw-r--r-- | kernel/signal.c | 48 | 
1 files changed, 31 insertions, 17 deletions
| diff --git a/kernel/signal.c b/kernel/signal.c index 08dfbd748cd2..677102789cf2 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2368,24 +2368,34 @@ relock:  }  /** - * block_sigmask - add @ka's signal mask to current->blocked - * @ka: action for @signr - * @signr: signal that has been successfully delivered + * signal_delivered -  + * @sig:		number of signal being delivered + * @info:		siginfo_t of signal being delivered + * @ka:			sigaction setting that chose the handler + * @regs:		user register state + * @stepping:		nonzero if debugger single-step or block-step in use   *   * This function should be called when a signal has succesfully been - * delivered. It adds the mask of signals for @ka to current->blocked - * so that they are blocked during the execution of the signal - * handler. In addition, @signr will be blocked unless %SA_NODEFER is - * set in @ka->sa.sa_flags. + * delivered. It updates the blocked signals accordingly (@ka->sa.sa_mask + * is always blocked, and the signal itself is blocked unless %SA_NODEFER + * is set in @ka->sa.sa_flags.  Tracing is notified.   */ -void block_sigmask(struct k_sigaction *ka, int signr) +void signal_delivered(int sig, siginfo_t *info, struct k_sigaction *ka, +			struct pt_regs *regs, int stepping)  {  	sigset_t blocked; +	/* A signal was successfully delivered, and the +	   saved sigmask was stored on the signal frame, +	   and will be restored by sigreturn.  So we can +	   simply clear the restore sigmask flag.  */ +	clear_restore_sigmask(); +  	sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask);  	if (!(ka->sa.sa_flags & SA_NODEFER)) -		sigaddset(&blocked, signr); +		sigaddset(&blocked, sig);  	set_current_blocked(&blocked); +	tracehook_signal_handler(sig, info, ka, regs, stepping);  }  /* @@ -2518,7 +2528,16 @@ static void __set_task_blocked(struct task_struct *tsk, const sigset_t *newset)   * It is wrong to change ->blocked directly, this helper should be used   * to ensure the process can't miss a shared signal we are going to block.   */ -void set_current_blocked(const sigset_t *newset) +void set_current_blocked(sigset_t *newset) +{ +	struct task_struct *tsk = current; +	sigdelsetmask(newset, sigmask(SIGKILL) | sigmask(SIGSTOP)); +	spin_lock_irq(&tsk->sighand->siglock); +	__set_task_blocked(tsk, newset); +	spin_unlock_irq(&tsk->sighand->siglock); +} + +void __set_current_blocked(const sigset_t *newset)  {  	struct task_struct *tsk = current; @@ -2558,7 +2577,7 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset)  		return -EINVAL;  	} -	set_current_blocked(&newset); +	__set_current_blocked(&newset);  	return 0;  } @@ -3132,7 +3151,7 @@ SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset,  			return -EINVAL;  		} -		set_current_blocked(&new_blocked); +		__set_current_blocked(&new_blocked);  	}  	if (oset) { @@ -3196,7 +3215,6 @@ SYSCALL_DEFINE1(ssetmask, int, newmask)  	int old = current->blocked.sig[0];  	sigset_t newset; -	siginitset(&newset, newmask & ~(sigmask(SIGKILL) | sigmask(SIGSTOP)));  	set_current_blocked(&newset);  	return old; @@ -3235,11 +3253,8 @@ SYSCALL_DEFINE0(pause)  #endif -#ifdef HAVE_SET_RESTORE_SIGMASK  int sigsuspend(sigset_t *set)  { -	sigdelsetmask(set, sigmask(SIGKILL)|sigmask(SIGSTOP)); -  	current->saved_sigmask = current->blocked;  	set_current_blocked(set); @@ -3248,7 +3263,6 @@ int sigsuspend(sigset_t *set)  	set_restore_sigmask();  	return -ERESTARTNOHAND;  } -#endif  #ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND  /** | 
