diff options
Diffstat (limited to 'kernel/signal.c')
| -rw-r--r-- | kernel/signal.c | 20 | 
1 files changed, 14 insertions, 6 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index ca92bcfeb322..45b4c1ffe14e 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -510,7 +510,8 @@ int unhandled_signal(struct task_struct *tsk, int sig)  	return !tsk->ptrace;  } -static void collect_signal(int sig, struct sigpending *list, siginfo_t *info) +static void collect_signal(int sig, struct sigpending *list, siginfo_t *info, +			   bool *resched_timer)  {  	struct sigqueue *q, *first = NULL; @@ -532,6 +533,12 @@ static void collect_signal(int sig, struct sigpending *list, siginfo_t *info)  still_pending:  		list_del_init(&first->list);  		copy_siginfo(info, &first->info); + +		*resched_timer = +			(first->flags & SIGQUEUE_PREALLOC) && +			(info->si_code == SI_TIMER) && +			(info->si_sys_private); +  		__sigqueue_free(first);  	} else {  		/* @@ -548,12 +555,12 @@ still_pending:  }  static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, -			siginfo_t *info) +			siginfo_t *info, bool *resched_timer)  {  	int sig = next_signal(pending, mask);  	if (sig) -		collect_signal(sig, pending, info); +		collect_signal(sig, pending, info, resched_timer);  	return sig;  } @@ -565,15 +572,16 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,   */  int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)  { +	bool resched_timer = false;  	int signr;  	/* We only dequeue private signals from ourselves, we don't let  	 * signalfd steal them  	 */ -	signr = __dequeue_signal(&tsk->pending, mask, info); +	signr = __dequeue_signal(&tsk->pending, mask, info, &resched_timer);  	if (!signr) {  		signr = __dequeue_signal(&tsk->signal->shared_pending, -					 mask, info); +					 mask, info, &resched_timer);  #ifdef CONFIG_POSIX_TIMERS  		/*  		 * itimer signal ? @@ -621,7 +629,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)  		current->jobctl |= JOBCTL_STOP_DEQUEUED;  	}  #ifdef CONFIG_POSIX_TIMERS -	if ((info->si_code & __SI_MASK) == __SI_TIMER && info->si_sys_private) { +	if (resched_timer) {  		/*  		 * Release the siglock to ensure proper locking order  		 * of timer locks outside of siglocks.  Note, we leave  | 
