]> git.hungrycats.org Git - linux/commitdiff
Fix thread group leader zombie leak
authorLinus Torvalds <torvalds@home.osdl.org>
Sun, 14 Dec 2003 10:28:27 +0000 (02:28 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Sun, 14 Dec 2003 10:28:27 +0000 (02:28 -0800)
Petr Vandrovec noticed a problem where the thread group leader
would not be properly reaped if the parent of the thread group
was ignoring SIGCHLD, and the thread group leader had exited
before the last sub-thread.

Fixed by Ingo Molnar.

kernel/exit.c

index 202d7eaf3245fae2444eed79fc752645b79d3aae..1f7e7545e1d05ec2d9cb83c71f79070bf7e9f9e9 100644 (file)
@@ -49,9 +49,11 @@ static void __unhash_process(struct task_struct *p)
 
 void release_task(struct task_struct * p)
 {
+       int zap_leader;
        task_t *leader;
        struct dentry *proc_dentry;
+
+repeat: 
        BUG_ON(p->state < TASK_ZOMBIE);
  
        atomic_dec(&p->user->processes);
@@ -70,10 +72,21 @@ void release_task(struct task_struct * p)
         * group, and the leader is zombie, then notify the
         * group leader's parent process. (if it wants notification.)
         */
+       zap_leader = 0;
        leader = p->group_leader;
-       if (leader != p && thread_group_empty(leader) &&
-                   leader->state == TASK_ZOMBIE && leader->exit_signal != -1)
+       if (leader != p && thread_group_empty(leader) && leader->state == TASK_ZOMBIE) {
+               BUG_ON(leader->exit_signal == -1);
                do_notify_parent(leader, leader->exit_signal);
+               /*
+                * If we were the last child thread and the leader has
+                * exited already, and the leader's parent ignores SIGCHLD,
+                * then we are the one who should release the leader.
+                *
+                * do_notify_parent() will have marked it self-reaping in
+                * that case.
+                */
+               zap_leader = (leader->exit_signal == -1);
+       }
 
        p->parent->cutime += p->utime + p->cutime;
        p->parent->cstime += p->stime + p->cstime;
@@ -88,6 +101,10 @@ void release_task(struct task_struct * p)
        proc_pid_flush(proc_dentry);
        release_thread(p);
        put_task_struct(p);
+
+       p = leader;
+       if (unlikely(zap_leader))
+               goto repeat;
 }
 
 /* we are using it only for SMP init */