aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2009-04-02 19:58:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-02 22:04:59 -0400
commit6d69cb87f05eef3b02370b2f7bae608ad2301a00 (patch)
tree69f38afc49df51a1a75fc5c7792ced6888af329d /kernel
parent95c3eb76dc07fd81289888ffc42948196b34b444 (diff)
ptrace: simplify ptrace_exit()->ignoring_children() path
ignoring_children() takes parent->sighand->siglock and checks k_sigaction[SIGCHLD] atomically. But this buys nothing, we can't get the "really" wrong result even if we race with sigaction(SIGCHLD). If we read the "stale" sa_handler/sa_flags we can pretend it was changed right after the check. Remove spin_lock(->siglock), and kill "int ign" which caches the result of ignoring_children() which becomes rather trivial. Perhaps it makes sense to export this helper, do_notify_parent() can use it too. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Cc: Jerome Marchand <jmarchan@redhat.com> Cc: Roland McGrath <roland@redhat.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c25
1 files changed, 8 insertions, 17 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 0c06b9efae3b..7a8311422930 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -732,19 +732,15 @@ static void exit_mm(struct task_struct * tsk)
732} 732}
733 733
734/* 734/*
735 * Return nonzero if @parent's children should reap themselves. 735 * Called with irqs disabled, returns true if childs should reap themselves.
736 *
737 * Called with write_lock_irq(&tasklist_lock) held.
738 */ 736 */
739static int ignoring_children(struct task_struct *parent) 737static int ignoring_children(struct sighand_struct *sigh)
740{ 738{
741 int ret; 739 int ret;
742 struct sighand_struct *psig = parent->sighand; 740 spin_lock(&sigh->siglock);
743 unsigned long flags; 741 ret = (sigh->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) ||
744 spin_lock_irqsave(&psig->siglock, flags); 742 (sigh->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT);
745 ret = (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN || 743 spin_unlock(&sigh->siglock);
746 (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT));
747 spin_unlock_irqrestore(&psig->siglock, flags);
748 return ret; 744 return ret;
749} 745}
750 746
@@ -757,7 +753,6 @@ static int ignoring_children(struct task_struct *parent)
757static void ptrace_exit(struct task_struct *parent, struct list_head *dead) 753static void ptrace_exit(struct task_struct *parent, struct list_head *dead)
758{ 754{
759 struct task_struct *p, *n; 755 struct task_struct *p, *n;
760 int ign = -1;
761 756
762 list_for_each_entry_safe(p, n, &parent->ptraced, ptrace_entry) { 757 list_for_each_entry_safe(p, n, &parent->ptraced, ptrace_entry) {
763 __ptrace_unlink(p); 758 __ptrace_unlink(p);
@@ -779,12 +774,8 @@ static void ptrace_exit(struct task_struct *parent, struct list_head *dead)
779 if (!task_detached(p) && thread_group_empty(p)) { 774 if (!task_detached(p) && thread_group_empty(p)) {
780 if (!same_thread_group(p->real_parent, parent)) 775 if (!same_thread_group(p->real_parent, parent))
781 do_notify_parent(p, p->exit_signal); 776 do_notify_parent(p, p->exit_signal);
782 else { 777 else if (ignoring_children(parent->sighand))
783 if (ign < 0) 778 p->exit_signal = -1;
784 ign = ignoring_children(parent);
785 if (ign)
786 p->exit_signal = -1;
787 }
788 } 779 }
789 780
790 if (task_detached(p)) { 781 if (task_detached(p)) {