aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/signal.h17
-rw-r--r--kernel/signal.c34
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
97static 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 */
632static 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 */
629static int rm_from_queue(unsigned long mask, struct sigpending *s) 656static int rm_from_queue(unsigned long mask, struct sigpending *s)
630{ 657{
@@ -2408,6 +2435,7 @@ int
2408do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) 2435do_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);