History

recalc_sigpending_tsk fixes

Steve Hawkes discovered a problem where recalc_sigpending_tsk was called in do_sigaction but no signal_wake_up call was made, preventing later signals from waking up blocked threads with TIF_SIGPENDING already set. In fact, the few other calls to recalc_sigpending_tsk outside the signals code are also subject to this problem in other race conditions. This change makes recalc_sigpending_tsk private to the signals code. It changes the outside calls, as well as do_sigaction, to use the new recalc_sigpending_and_wake instead.

Roland McGrath committed 19 years ago

Commit 7bb44ad1 parent 3c6df2a4 files · +28 −17Browse files

Showing the changes to kernel (3 of 4 files). Show all

Unified · Split

3 files
  1. kernel/exit.c +2 −5
  2. kernel/power/process.c +1 −1
  3. kernel/signal.c +18 −6
kernel/exit.c+2−5
@@ -762,11 +762,8 @@ static void exit_notify(struct task_struct *tsk) · 761 unmodified lines
762 read_lock(&tasklist_lock);762 read_lock(&tasklist_lock);
763 spin_lock_irq(&tsk->sighand->siglock);763 spin_lock_irq(&tsk->sighand->siglock);
764 for (t = next_thread(tsk); t != tsk; t = next_thread(t))764 for (t = next_thread(tsk); t != tsk; t = next_thread(t))
765 if (!signal_pending(t) && !(t->flags & PF_EXITING)) {765 if (!signal_pending(t) && !(t->flags & PF_EXITING))
766 recalc_sigpending_tsk(t);766 recalc_sigpending_and_wake(t);
767 if (signal_pending(t))
768 signal_wake_up(t, 0);
769 }
770 spin_unlock_irq(&tsk->sighand->siglock);767 spin_unlock_irq(&tsk->sighand->siglock);
771 read_unlock(&tasklist_lock);768 read_unlock(&tasklist_lock);
772 }769 }
kernel/power/process.c+1−1
@@ -101,7 +101,7 @@ static void cancel_freezing(struct task_struct *p) · 100 unmodified lines
101 pr_debug(" clean up: %s\n", p->comm);101 pr_debug(" clean up: %s\n", p->comm);
102 do_not_freeze(p);102 do_not_freeze(p);
103 spin_lock_irqsave(&p->sighand->siglock, flags);103 spin_lock_irqsave(&p->sighand->siglock, flags);
104 recalc_sigpending_tsk(p);104 recalc_sigpending_and_wake(p);
105 spin_unlock_irqrestore(&p->sighand->siglock, flags);105 spin_unlock_irqrestore(&p->sighand->siglock, flags);
106 }106 }
107}107}
kernel/signal.c+18−6
@@ -96,15 +96,27 @@ static inline int has_pending_signals(sigset_t *signal, sigset_t *blocked) · 95 unmodified lines
96 96
97#define PENDING(p,b) has_pending_signals(&(p)->signal, (b))97#define PENDING(p,b) has_pending_signals(&(p)->signal, (b))
98 98
99fastcall void recalc_sigpending_tsk(struct task_struct *t)99static int recalc_sigpending_tsk(struct task_struct *t)
100{100{
101 if (t->signal->group_stop_count > 0 ||101 if (t->signal->group_stop_count > 0 ||
102 (freezing(t)) ||102 (freezing(t)) ||
103 PENDING(&t->pending, &t->blocked) ||103 PENDING(&t->pending, &t->blocked) ||
104 PENDING(&t->signal->shared_pending, &t->blocked))104 PENDING(&t->signal->shared_pending, &t->blocked)) {
105 set_tsk_thread_flag(t, TIF_SIGPENDING);105 set_tsk_thread_flag(t, TIF_SIGPENDING);
106 else106 return 1;
107 clear_tsk_thread_flag(t, TIF_SIGPENDING);107 }
108 clear_tsk_thread_flag(t, TIF_SIGPENDING);
109 return 0;
110}
111
112/*
113 * After recalculating TIF_SIGPENDING, we need to make sure the task wakes up.
114 * This is superfluous when called on current, the wakeup is a harmless no-op.
115 */
116void recalc_sigpending_and_wake(struct task_struct *t)
117{
118 if (recalc_sigpending_tsk(t))
119 signal_wake_up(t, 0);
108}120}
109 121
110void recalc_sigpending(void)122void recalc_sigpending(void)
@@ -744,7 +756,7 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t) · 633 unmodified lines
744 action->sa.sa_handler = SIG_DFL;756 action->sa.sa_handler = SIG_DFL;
745 if (blocked) {757 if (blocked) {
746 sigdelset(&t->blocked, sig);758 sigdelset(&t->blocked, sig);
747 recalc_sigpending_tsk(t);759 recalc_sigpending_and_wake(t);
748 }760 }
749 }761 }
750 ret = specific_send_sig_info(sig, info, t);762 ret = specific_send_sig_info(sig, info, t);
@@ -2273,7 +2285,7 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) · 1522 unmodified lines
2273 rm_from_queue_full(&mask, &t->signal->shared_pending);2285 rm_from_queue_full(&mask, &t->signal->shared_pending);
2274 do {2286 do {
2275 rm_from_queue_full(&mask, &t->pending);2287 rm_from_queue_full(&mask, &t->pending);
2276 recalc_sigpending_tsk(t);2288 recalc_sigpending_and_wake(t);
2277 t = next_thread(t);2289 t = next_thread(t);
2278 } while (t != current);2290 } while (t != current);
2279 }2291 }