diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 63 |
1 files changed, 59 insertions, 4 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index e1d7ad8e6ab1..99fa8ff06fd9 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -688,6 +688,48 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, kernel_siginfo_t *in | |||
688 | } | 688 | } |
689 | EXPORT_SYMBOL_GPL(dequeue_signal); | 689 | EXPORT_SYMBOL_GPL(dequeue_signal); |
690 | 690 | ||
691 | static int dequeue_synchronous_signal(kernel_siginfo_t *info) | ||
692 | { | ||
693 | struct task_struct *tsk = current; | ||
694 | struct sigpending *pending = &tsk->pending; | ||
695 | struct sigqueue *q, *sync = NULL; | ||
696 | |||
697 | /* | ||
698 | * Might a synchronous signal be in the queue? | ||
699 | */ | ||
700 | if (!((pending->signal.sig[0] & ~tsk->blocked.sig[0]) & SYNCHRONOUS_MASK)) | ||
701 | return 0; | ||
702 | |||
703 | /* | ||
704 | * Return the first synchronous signal in the queue. | ||
705 | */ | ||
706 | list_for_each_entry(q, &pending->list, list) { | ||
707 | /* Synchronous signals have a postive si_code */ | ||
708 | if ((q->info.si_code > SI_USER) && | ||
709 | (sigmask(q->info.si_signo) & SYNCHRONOUS_MASK)) { | ||
710 | sync = q; | ||
711 | goto next; | ||
712 | } | ||
713 | } | ||
714 | return 0; | ||
715 | next: | ||
716 | /* | ||
717 | * Check if there is another siginfo for the same signal. | ||
718 | */ | ||
719 | list_for_each_entry_continue(q, &pending->list, list) { | ||
720 | if (q->info.si_signo == sync->info.si_signo) | ||
721 | goto still_pending; | ||
722 | } | ||
723 | |||
724 | sigdelset(&pending->signal, sync->info.si_signo); | ||
725 | recalc_sigpending(); | ||
726 | still_pending: | ||
727 | list_del_init(&sync->list); | ||
728 | copy_siginfo(info, &sync->info); | ||
729 | __sigqueue_free(sync); | ||
730 | return info->si_signo; | ||
731 | } | ||
732 | |||
691 | /* | 733 | /* |
692 | * Tell a process that it has a new active signal.. | 734 | * Tell a process that it has a new active signal.. |
693 | * | 735 | * |
@@ -1057,10 +1099,9 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc | |||
1057 | 1099 | ||
1058 | result = TRACE_SIGNAL_DELIVERED; | 1100 | result = TRACE_SIGNAL_DELIVERED; |
1059 | /* | 1101 | /* |
1060 | * Skip useless siginfo allocation for SIGKILL SIGSTOP, | 1102 | * Skip useless siginfo allocation for SIGKILL and kernel threads. |
1061 | * and kernel threads. | ||
1062 | */ | 1103 | */ |
1063 | if (sig_kernel_only(sig) || (t->flags & PF_KTHREAD)) | 1104 | if ((sig == SIGKILL) || (t->flags & PF_KTHREAD)) |
1064 | goto out_set; | 1105 | goto out_set; |
1065 | 1106 | ||
1066 | /* | 1107 | /* |
@@ -2394,6 +2435,11 @@ relock: | |||
2394 | goto relock; | 2435 | goto relock; |
2395 | } | 2436 | } |
2396 | 2437 | ||
2438 | /* Has this task already been marked for death? */ | ||
2439 | ksig->info.si_signo = signr = SIGKILL; | ||
2440 | if (signal_group_exit(signal)) | ||
2441 | goto fatal; | ||
2442 | |||
2397 | for (;;) { | 2443 | for (;;) { |
2398 | struct k_sigaction *ka; | 2444 | struct k_sigaction *ka; |
2399 | 2445 | ||
@@ -2407,7 +2453,15 @@ relock: | |||
2407 | goto relock; | 2453 | goto relock; |
2408 | } | 2454 | } |
2409 | 2455 | ||
2410 | signr = dequeue_signal(current, ¤t->blocked, &ksig->info); | 2456 | /* |
2457 | * Signals generated by the execution of an instruction | ||
2458 | * need to be delivered before any other pending signals | ||
2459 | * so that the instruction pointer in the signal stack | ||
2460 | * frame points to the faulting instruction. | ||
2461 | */ | ||
2462 | signr = dequeue_synchronous_signal(&ksig->info); | ||
2463 | if (!signr) | ||
2464 | signr = dequeue_signal(current, ¤t->blocked, &ksig->info); | ||
2411 | 2465 | ||
2412 | if (!signr) | 2466 | if (!signr) |
2413 | break; /* will return 0 */ | 2467 | break; /* will return 0 */ |
@@ -2489,6 +2543,7 @@ relock: | |||
2489 | continue; | 2543 | continue; |
2490 | } | 2544 | } |
2491 | 2545 | ||
2546 | fatal: | ||
2492 | spin_unlock_irq(&sighand->siglock); | 2547 | spin_unlock_irq(&sighand->siglock); |
2493 | 2548 | ||
2494 | /* | 2549 | /* |