summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/signal.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index b8fc6a05c031..b7ac6a557ddb 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1109,21 +1109,31 @@ static int kill_something_info(int sig, struct siginfo *info, int pid)
* These are for backward compatibility with the rest of the kernel source.
*/
+/*
+ * XXX should probably nix these interfaces and update the kernel
+ * to specify explicitly whether the signal is a group signal or
+ * specific to a thread.
+ */
int
send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
{
int ret;
- /* XXX should nix these interfaces and update the kernel */
+ /*
+ * We need the tasklist lock even for the specific
+ * thread case (when we don't need to follow the group
+ * lists) in order to avoid races with "p->sighand"
+ * going away or changing from under us.
+ */
+ read_lock(&tasklist_lock);
if (T(sig, SIG_KERNEL_BROADCAST_MASK)) {
- read_lock(&tasklist_lock);
ret = group_send_sig_info(sig, info, p);
- read_unlock(&tasklist_lock);
} else {
spin_lock_irq(&p->sighand->siglock);
ret = specific_send_sig_info(sig, info, p);
spin_unlock_irq(&p->sighand->siglock);
}
+ read_unlock(&tasklist_lock);
return ret;
}