diff options
| -rw-r--r-- | include/linux/signal.h | 17 | ||||
| -rw-r--r-- | kernel/signal.c | 34 |
2 files changed, 49 insertions, 2 deletions
diff --git a/include/linux/signal.h b/include/linux/signal.h index ea9eff16c4b7..b7d093520bb6 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h | |||
| @@ -94,6 +94,23 @@ static inline int sigfindinword(unsigned long word) | |||
| 94 | 94 | ||
| 95 | #endif /* __HAVE_ARCH_SIG_BITOPS */ | 95 | #endif /* __HAVE_ARCH_SIG_BITOPS */ |
| 96 | 96 | ||
| 97 | static inline int sigisemptyset(sigset_t *set) | ||
| 98 | { | ||
| 99 | extern void _NSIG_WORDS_is_unsupported_size(void); | ||
| 100 | switch (_NSIG_WORDS) { | ||
| 101 | case 4: | ||
| 102 | return (set->sig[3] | set->sig[2] | | ||
| 103 | set->sig[1] | set->sig[0]) == 0; | ||
| 104 | case 2: | ||
| 105 | return (set->sig[1] | set->sig[0]) == 0; | ||
| 106 | case 1: | ||
| 107 | return set->sig[0] == 0; | ||
| 108 | default: | ||
| 109 | _NSIG_WORDS_is_unsupported_size(); | ||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 97 | #define sigmask(sig) (1UL << ((sig) - 1)) | 114 | #define sigmask(sig) (1UL << ((sig) - 1)) |
| 98 | 115 | ||
| 99 | #ifndef __HAVE_ARCH_SIG_SETOPS | 116 | #ifndef __HAVE_ARCH_SIG_SETOPS |
diff --git a/kernel/signal.c b/kernel/signal.c index 9b6fda5e87f1..e20724af9b36 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -625,6 +625,33 @@ void signal_wake_up(struct task_struct *t, int resume) | |||
| 625 | * Returns 1 if any signals were found. | 625 | * Returns 1 if any signals were found. |
| 626 | * | 626 | * |
| 627 | * All callers must be holding the siglock. | 627 | * All callers must be holding the siglock. |
| 628 | * | ||
| 629 | * This version takes a sigset mask and looks at all signals, | ||
| 630 | * not just those in the first mask word. | ||
| 631 | */ | ||
| 632 | static int rm_from_queue_full(sigset_t *mask, struct sigpending *s) | ||
| 633 | { | ||
| 634 | struct sigqueue *q, *n; | ||
| 635 | sigset_t m; | ||
| 636 | |||
| 637 | sigandsets(&m, mask, &s->signal); | ||
| 638 | if (sigisemptyset(&m)) | ||
| 639 | return 0; | ||
| 640 | |||
| 641 | signandsets(&s->signal, &s->signal, mask); | ||
| 642 | list_for_each_entry_safe(q, n, &s->list, list) { | ||
| 643 | if (sigismember(mask, q->info.si_signo)) { | ||
| 644 | list_del_init(&q->list); | ||
| 645 | __sigqueue_free(q); | ||
| 646 | } | ||
| 647 | } | ||
| 648 | return 1; | ||
| 649 | } | ||
| 650 | /* | ||
| 651 | * Remove signals in mask from the pending set and queue. | ||
| 652 | * Returns 1 if any signals were found. | ||
| 653 | * | ||
| 654 | * All callers must be holding the siglock. | ||
| 628 | */ | 655 | */ |
| 629 | static int rm_from_queue(unsigned long mask, struct sigpending *s) | 656 | static int rm_from_queue(unsigned long mask, struct sigpending *s) |
| 630 | { | 657 | { |
| @@ -2408,6 +2435,7 @@ int | |||
| 2408 | do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) | 2435 | do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) |
| 2409 | { | 2436 | { |
| 2410 | struct k_sigaction *k; | 2437 | struct k_sigaction *k; |
| 2438 | sigset_t mask; | ||
| 2411 | 2439 | ||
| 2412 | if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig))) | 2440 | if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig))) |
| 2413 | return -EINVAL; | 2441 | return -EINVAL; |
| @@ -2455,9 +2483,11 @@ do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) | |||
| 2455 | *k = *act; | 2483 | *k = *act; |
| 2456 | sigdelsetmask(&k->sa.sa_mask, | 2484 | sigdelsetmask(&k->sa.sa_mask, |
| 2457 | sigmask(SIGKILL) | sigmask(SIGSTOP)); | 2485 | sigmask(SIGKILL) | sigmask(SIGSTOP)); |
| 2458 | rm_from_queue(sigmask(sig), &t->signal->shared_pending); | 2486 | sigemptyset(&mask); |
| 2487 | sigaddset(&mask, sig); | ||
| 2488 | rm_from_queue_full(&mask, &t->signal->shared_pending); | ||
| 2459 | do { | 2489 | do { |
| 2460 | rm_from_queue(sigmask(sig), &t->pending); | 2490 | rm_from_queue_full(&mask, &t->pending); |
| 2461 | recalc_sigpending_tsk(t); | 2491 | recalc_sigpending_tsk(t); |
| 2462 | t = next_thread(t); | 2492 | t = next_thread(t); |
| 2463 | } while (t != current); | 2493 | } while (t != current); |
