exit: ptrace: shift "reap dead" code from exit_ptrace() to forget_original_parent()
[cascardo/linux.git] / kernel / exit.c
index 5d30019..9c9526d 100644 (file)
@@ -529,15 +529,7 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
 static void reparent_leader(struct task_struct *father, struct task_struct *p,
                                struct list_head *dead)
 {
-       list_move_tail(&p->sibling, &p->real_parent->children);
-
-       if (p->exit_state == EXIT_DEAD)
-               return;
-       /*
-        * If this is a threaded reparent there is no need to
-        * notify anyone anything has happened.
-        */
-       if (same_thread_group(p->real_parent, father))
+       if (unlikely(p->exit_state == EXIT_DEAD))
                return;
 
        /* We don't want people slaying init. */
@@ -548,7 +540,7 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
            p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
                if (do_notify_parent(p, p->exit_signal)) {
                        p->exit_state = EXIT_DEAD;
-                       list_move_tail(&p->sibling, dead);
+                       list_add(&p->ptrace_entry, dead);
                }
        }
 
@@ -557,38 +549,37 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
 
 static void forget_original_parent(struct task_struct *father)
 {
-       struct task_struct *p, *n, *reaper;
+       struct task_struct *p, *t, *n, *reaper;
        LIST_HEAD(dead_children);
 
        write_lock_irq(&tasklist_lock);
-       /*
-        * Note that exit_ptrace() and find_new_reaper() might
-        * drop tasklist_lock and reacquire it.
-        */
-       exit_ptrace(father);
-       reaper = find_new_reaper(father);
+       if (unlikely(!list_empty(&father->ptraced)))
+               exit_ptrace(father, &dead_children);
 
-       list_for_each_entry_safe(p, n, &father->children, sibling) {
-               struct task_struct *t = p;
-
-               do {
+       /* Can drop and reacquire tasklist_lock */
+       reaper = find_new_reaper(father);
+       list_for_each_entry(p, &father->children, sibling) {
+               for_each_thread(p, t) {
                        t->real_parent = reaper;
-                       if (t->parent == father) {
-                               BUG_ON(t->ptrace);
+                       BUG_ON((!t->ptrace) != (t->parent == father));
+                       if (likely(!t->ptrace))
                                t->parent = t->real_parent;
-                       }
                        if (t->pdeath_signal)
                                group_send_sig_info(t->pdeath_signal,
                                                    SEND_SIG_NOINFO, t);
-               } while_each_thread(p, t);
-               reparent_leader(father, p, &dead_children);
+               }
+               /*
+                * If this is a threaded reparent there is no need to
+                * notify anyone anything has happened.
+                */
+               if (!same_thread_group(reaper, father))
+                       reparent_leader(father, p, &dead_children);
        }
+       list_splice_tail_init(&father->children, &reaper->children);
        write_unlock_irq(&tasklist_lock);
 
-       BUG_ON(!list_empty(&father->children));
-
-       list_for_each_entry_safe(p, n, &dead_children, sibling) {
-               list_del_init(&p->sibling);
+       list_for_each_entry_safe(p, n, &dead_children, ptrace_entry) {
+               list_del_init(&p->ptrace_entry);
                release_task(p);
        }
 }
@@ -997,6 +988,8 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
 
                get_task_struct(p);
                read_unlock(&tasklist_lock);
+               sched_annotate_sleep();
+
                if ((exit_code & 0x7f) == 0) {
                        why = CLD_EXITED;
                        status = exit_code >> 8;
@@ -1079,6 +1072,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
         * thread can reap it because we its state == DEAD/TRACE.
         */
        read_unlock(&tasklist_lock);
+       sched_annotate_sleep();
 
        retval = wo->wo_rusage
                ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0;
@@ -1210,6 +1204,7 @@ unlock_sig:
        pid = task_pid_vnr(p);
        why = ptrace ? CLD_TRAPPED : CLD_STOPPED;
        read_unlock(&tasklist_lock);
+       sched_annotate_sleep();
 
        if (unlikely(wo->wo_flags & WNOWAIT))
                return wait_noreap_copyout(wo, p, pid, uid, why, exit_code);
@@ -1272,6 +1267,7 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p)
        pid = task_pid_vnr(p);
        get_task_struct(p);
        read_unlock(&tasklist_lock);
+       sched_annotate_sleep();
 
        if (!wo->wo_info) {
                retval = wo->wo_rusage