]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/exit.c
doc: move vm/00-INDEX to Documentation/vm
[linux-2.6-omap-h63xx.git] / kernel / exit.c
index 993369ee94d1ebb8d4c7675a821e90abf8a1737e..2c704c86edb3200864d4ec950c4e2bd89cbf3443 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/resource.h>
 #include <linux/blkdev.h>
 #include <linux/task_io_accounting_ops.h>
-#include <linux/freezer.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -93,10 +92,9 @@ static void __exit_signal(struct task_struct *tsk)
                 * If there is any task waiting for the group exit
                 * then notify it:
                 */
-               if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count) {
+               if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count)
                        wake_up_process(sig->group_exit_task);
-                       sig->group_exit_task = NULL;
-               }
+
                if (tsk == sig->curr_target)
                        sig->curr_target = next_thread(tsk);
                /*
@@ -111,6 +109,7 @@ static void __exit_signal(struct task_struct *tsk)
                 */
                sig->utime = cputime_add(sig->utime, tsk->utime);
                sig->stime = cputime_add(sig->stime, tsk->stime);
+               sig->gtime = cputime_add(sig->gtime, tsk->gtime);
                sig->min_flt += tsk->min_flt;
                sig->maj_flt += tsk->maj_flt;
                sig->nvcsw += tsk->nvcsw;
@@ -592,17 +591,6 @@ static void exit_mm(struct task_struct * tsk)
        mmput(mm);
 }
 
-static inline void
-choose_new_parent(struct task_struct *p, struct task_struct *reaper)
-{
-       /*
-        * Make sure we're not reparenting to ourselves and that
-        * the parent is not a zombie.
-        */
-       BUG_ON(p == reaper || reaper->exit_state);
-       p->real_parent = reaper;
-}
-
 static void
 reparent_thread(struct task_struct *p, struct task_struct *father, int traced)
 {
@@ -710,7 +698,7 @@ forget_original_parent(struct task_struct *father, struct list_head *to_release)
 
                if (father == p->real_parent) {
                        /* reparent with a reaper, real father it's us */
-                       choose_new_parent(p, reaper);
+                       p->real_parent = reaper;
                        reparent_thread(p, father, 0);
                } else {
                        /* reparent ptraced task to its real parent */
@@ -731,7 +719,7 @@ forget_original_parent(struct task_struct *father, struct list_head *to_release)
        }
        list_for_each_safe(_p, _n, &father->ptrace_children) {
                p = list_entry(_p, struct task_struct, ptrace_list);
-               choose_new_parent(p, reaper);
+               p->real_parent = reaper;
                reparent_thread(p, father, 1);
        }
 }
@@ -758,13 +746,11 @@ static void exit_notify(struct task_struct *tsk)
                 * Now we'll wake all the threads in the group just to make
                 * sure someone gets all the pending signals.
                 */
-               read_lock(&tasklist_lock);
                spin_lock_irq(&tsk->sighand->siglock);
                for (t = next_thread(tsk); t != tsk; t = next_thread(t))
                        if (!signal_pending(t) && !(t->flags & PF_EXITING))
                                recalc_sigpending_and_wake(t);
                spin_unlock_irq(&tsk->sighand->siglock);
-               read_unlock(&tasklist_lock);
        }
 
        write_lock_irq(&tasklist_lock);
@@ -792,9 +778,8 @@ static void exit_notify(struct task_struct *tsk)
         * and we were the only connection outside, so our pgrp
         * is about to become orphaned.
         */
-        
        t = tsk->real_parent;
-       
+
        pgrp = task_pgrp(tsk);
        if ((task_pgrp(t) != pgrp) &&
            (task_session(t) == task_session(tsk)) &&
@@ -841,6 +826,11 @@ static void exit_notify(struct task_struct *tsk)
                state = EXIT_DEAD;
        tsk->exit_state = state;
 
+       if (thread_group_leader(tsk) &&
+           tsk->signal->notify_count < 0 &&
+           tsk->signal->group_exit_task)
+               wake_up_process(tsk->signal->group_exit_task);
+
        write_unlock_irq(&tasklist_lock);
 
        list_for_each_safe(_p, _n, &ptrace_dead) {
@@ -882,6 +872,14 @@ static void check_stack_usage(void)
 static inline void check_stack_usage(void) {}
 #endif
 
+static inline void exit_child_reaper(struct task_struct *tsk)
+{
+       if (likely(tsk->group_leader != child_reaper(tsk)))
+               return;
+
+       panic("Attempted to kill init!");
+}
+
 fastcall NORET_TYPE void do_exit(long code)
 {
        struct task_struct *tsk = current;
@@ -895,13 +893,6 @@ fastcall NORET_TYPE void do_exit(long code)
                panic("Aiee, killing interrupt handler!");
        if (unlikely(!tsk->pid))
                panic("Attempted to kill the idle task!");
-       if (unlikely(tsk == child_reaper(tsk))) {
-               if (tsk->nsproxy->pid_ns != &init_pid_ns)
-                       tsk->nsproxy->pid_ns->child_reaper = init_pid_ns.child_reaper;
-               else
-                       panic("Attempted to kill init!");
-       }
-
 
        if (unlikely(current->ptrace & PT_TRACE_EXIT)) {
                current->ptrace_message = code;
@@ -931,13 +922,13 @@ fastcall NORET_TYPE void do_exit(long code)
                schedule();
        }
 
+       tsk->flags |= PF_EXITING;
        /*
         * tsk->flags are checked in the futex code to protect against
         * an exiting task cleaning up the robust pi futexes.
         */
-       spin_lock_irq(&tsk->pi_lock);
-       tsk->flags |= PF_EXITING;
-       spin_unlock_irq(&tsk->pi_lock);
+       smp_mb();
+       spin_unlock_wait(&tsk->pi_lock);
 
        if (unlikely(in_atomic()))
                printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",
@@ -951,15 +942,18 @@ fastcall NORET_TYPE void do_exit(long code)
        }
        group_dead = atomic_dec_and_test(&tsk->signal->live);
        if (group_dead) {
+               exit_child_reaper(tsk);
                hrtimer_cancel(&tsk->signal->real_timer);
                exit_itimers(tsk->signal);
        }
        acct_collect(code, group_dead);
+#ifdef CONFIG_FUTEX
        if (unlikely(tsk->robust_list))
                exit_robust_list(tsk);
-#if defined(CONFIG_FUTEX) && defined(CONFIG_COMPAT)
+#ifdef CONFIG_COMPAT
        if (unlikely(tsk->compat_robust_list))
                compat_exit_robust_list(tsk);
+#endif
 #endif
        if (group_dead)
                tty_audit_exit();
@@ -995,6 +989,7 @@ fastcall NORET_TYPE void do_exit(long code)
        mpol_free(tsk->mempolicy);
        tsk->mempolicy = NULL;
 #endif
+#ifdef CONFIG_FUTEX
        /*
         * This must happen late, after the PID is not
         * hashed anymore:
@@ -1003,6 +998,7 @@ fastcall NORET_TYPE void do_exit(long code)
                exit_pi_state_list(tsk);
        if (unlikely(current->pi_state_cache))
                kfree(current->pi_state_cache);
+#endif
        /*
         * Make sure we are holding no locks:
         */
@@ -1167,8 +1163,7 @@ static int wait_task_zombie(struct task_struct *p, int noreap,
                            int __user *stat_addr, struct rusage __user *ru)
 {
        unsigned long state;
-       int retval;
-       int status;
+       int retval, status, traced;
 
        if (unlikely(noreap)) {
                pid_t pid = p->pid;
@@ -1202,15 +1197,11 @@ static int wait_task_zombie(struct task_struct *p, int noreap,
                BUG_ON(state != EXIT_DEAD);
                return 0;
        }
-       if (unlikely(p->exit_signal == -1 && p->ptrace == 0)) {
-               /*
-                * This can only happen in a race with a ptraced thread
-                * dying on another processor.
-                */
-               return 0;
-       }
 
-       if (likely(p->real_parent == p->parent) && likely(p->signal)) {
+       /* traced means p->ptrace, but not vice versa */
+       traced = (p->real_parent != p->parent);
+
+       if (likely(!traced)) {
                struct signal_struct *psig;
                struct signal_struct *sig;
 
@@ -1242,6 +1233,11 @@ static int wait_task_zombie(struct task_struct *p, int noreap,
                        cputime_add(p->stime,
                        cputime_add(sig->stime,
                                    sig->cstime)));
+               psig->cgtime =
+                       cputime_add(psig->cgtime,
+                       cputime_add(p->gtime,
+                       cputime_add(sig->gtime,
+                                   sig->cgtime)));
                psig->cmin_flt +=
                        p->min_flt + sig->min_flt + sig->cmin_flt;
                psig->cmaj_flt +=
@@ -1292,35 +1288,30 @@ static int wait_task_zombie(struct task_struct *p, int noreap,
                retval = put_user(p->pid, &infop->si_pid);
        if (!retval && infop)
                retval = put_user(p->uid, &infop->si_uid);
-       if (retval) {
-               // TODO: is this safe?
-               p->exit_state = EXIT_ZOMBIE;
-               return retval;
-       }
-       retval = p->pid;
-       if (p->real_parent != p->parent) {
+       if (!retval)
+               retval = p->pid;
+
+       if (traced) {
                write_lock_irq(&tasklist_lock);
-               /* Double-check with lock held.  */
-               if (p->real_parent != p->parent) {
-                       __ptrace_unlink(p);
-                       // TODO: is this safe?
-                       p->exit_state = EXIT_ZOMBIE;
-                       /*
-                        * If this is not a detached task, notify the parent.
-                        * If it's still not detached after that, don't release
-                        * it now.
-                        */
+               /* We dropped tasklist, ptracer could die and untrace */
+               ptrace_unlink(p);
+               /*
+                * If this is not a detached task, notify the parent.
+                * If it's still not detached after that, don't release
+                * it now.
+                */
+               if (p->exit_signal != -1) {
+                       do_notify_parent(p, p->exit_signal);
                        if (p->exit_signal != -1) {
-                               do_notify_parent(p, p->exit_signal);
-                               if (p->exit_signal != -1)
-                                       p = NULL;
+                               p->exit_state = EXIT_ZOMBIE;
+                               p = NULL;
                        }
                }
                write_unlock_irq(&tasklist_lock);
        }
        if (p != NULL)
                release_task(p);
-       BUG_ON(!retval);
+
        return retval;
 }
 
@@ -1339,7 +1330,7 @@ static int wait_task_stopped(struct task_struct *p, int delayed_group_leader,
        if (!p->exit_code)
                return 0;
        if (delayed_group_leader && !(p->ptrace & PT_PTRACED) &&
-           p->signal && p->signal->group_stop_count > 0)
+           p->signal->group_stop_count > 0)
                /*
                 * A group stop is in progress and this is the group leader.
                 * We won't report until all threads have stopped.
@@ -1453,9 +1444,6 @@ static int wait_task_continued(struct task_struct *p, int noreap,
        pid_t pid;
        uid_t uid;
 
-       if (unlikely(!p->signal))
-               return 0;
-
        if (!(p->signal->flags & SIGNAL_STOP_CONTINUED))
                return 0;