]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] spurious SIGCHLD from dying thread group leader
authorRoland McGrath <roland@redhat.com>
Tue, 5 Aug 2003 15:30:45 +0000 (08:30 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Tue, 5 Aug 2003 15:30:45 +0000 (08:30 -0700)
A dying initial thread (thread group leader) sends SIGCHLD when it exits,
but it ought to wait until all other threads exit as well.  The cases of
secondary threads exitting first were handled properly, but not this one.

This exit.c patch fixes that test case, and I think catches the other
potential bugs of this kind as well.  The signal.c change adds some bug
catchers, the second of which will trip on the test case in the absence
of the exit.c fix.

kernel/exit.c
kernel/signal.c

index 7792bb1268ff17a4cae369b9bde0bbc468e9a685..d5f45b814d1fe125a4de1697ec557a3da44a28f6 100644 (file)
@@ -495,7 +495,8 @@ static inline void reparent_thread(task_t *p, task_t *father, int traced)
                /* If we'd notified the old parent about this child's death,
                 * also notify the new parent.
                 */
-               if (p->state == TASK_ZOMBIE && p->exit_signal != -1)
+               if (p->state == TASK_ZOMBIE && p->exit_signal != -1 &&
+                   thread_group_empty(p))
                        do_notify_parent(p, p->exit_signal);
        }
 
@@ -546,7 +547,8 @@ static inline void forget_original_parent(struct task_struct * father)
                        reparent_thread(p, father, 0);
                } else {
                        ptrace_unlink (p);
-                       if (p->state == TASK_ZOMBIE && p->exit_signal != -1)
+                       if (p->state == TASK_ZOMBIE && p->exit_signal != -1 &&
+                           thread_group_empty(p))
                                do_notify_parent(p, p->exit_signal);
                }
        }
@@ -649,7 +651,7 @@ static void exit_notify(struct task_struct *tsk)
         * send it a SIGCHLD instead of honoring exit_signal.  exit_signal
         * only has special meaning to our real parent.
         */
-       if (tsk->exit_signal != -1) {
+       if (tsk->exit_signal != -1 && thread_group_empty(tsk)) {
                int signal = tsk->parent == tsk->real_parent ? tsk->exit_signal : SIGCHLD;
                do_notify_parent(tsk, signal);
        } else if (tsk->ptrace) {
index cd0690a66f244ad06975ba0f0f9667d90911db46..208e924cc9f425d13953ad2678c567a4197f6355 100644 (file)
@@ -1396,6 +1396,9 @@ void do_notify_parent(struct task_struct *tsk, int sig)
        if (sig == -1)
                BUG();
 
+       BUG_ON(tsk->group_leader != tsk && tsk->group_leader->state != TASK_ZOMBIE && !tsk->ptrace);
+       BUG_ON(tsk->group_leader == tsk && !thread_group_empty(tsk) && !tsk->ptrace);
+
        info.si_signo = sig;
        info.si_errno = 0;
        info.si_pid = tsk->pid;