tsk->files = NULL; task_unlock(tsk); put_files_struct(files); }} void exit_files(struct task_struct *tsk){ __exit_files(tsk);} static inline void __put_fs_struct(struct fs_struct *fs){ /* No need to hold fs->lock if we are killing it */ if (atomic_dec_and_test(&fs->count)) { dput(fs->root); mntput(fs->rootmnt); dput(fs->pwd); mntput(fs->pwdmnt); if (fs->altroot) { dput(fs->altroot); mntput(fs->altrootmnt); } kmem_cache_free(fs_cachep, fs); }} void put_fs_struct(struct fs_struct *fs){ __put_fs_struct(fs);} static inline void __exit_fs(struct task_struct *tsk){ struct fs_struct * fs = tsk->fs; if (fs) { task_lock(tsk); tsk->fs = NULL; task_unlock(tsk); __put_fs_struct(fs); }} void exit_fs(struct task_struct *tsk){ __exit_fs(tsk);} EXPORT_SYMBOL_GPL(exit_fs); /* * Turn us into a lazy TLB process if we * aren't already.. */static void exit_mm(struct task_struct * tsk){ struct mm_struct *mm = tsk->mm; mm_release(tsk, mm); if (!mm) return; /* * Serialize with any possible pending coredump. * We must hold mmap_sem around checking core_waiters * and clearing tsk->mm. The core-inducing thread * will increment core_waiters for each thread in the * group with ->mm != NULL. */ down_read(&mm->mmap_sem); if (mm->core_waiters) { up_read(&mm->mmap_sem); down_write(&mm->mmap_sem); if (!--mm->core_waiters) complete(mm->core_startup_done); up_write(&mm->mmap_sem); wait_for_completion(&mm->core_done); down_read(&mm->mmap_sem); } atomic_inc(&mm->mm_count); if (mm != tsk->active_mm) BUG(); /* more a memory barrier than a real lock */ task_lock(tsk); tsk->mm = NULL; up_read(&mm->mmap_sem); enter_lazy_tlb(mm, current); task_unlock(tsk); mmput(mm);} static inline void choose_new_parent(task_t *p, task_t *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(task_t *p, task_t *father, int traced){ /* We don't want people slaying init. */ if (p->exit_signal != -1) p->exit_signal = SIGCHLD; if (p->pdeath_signal) /* We already hold the tasklist_lock here. */ group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p); /* Move the child from its dying parent to the new one. */ if (unlikely(traced)) { /* Preserve ptrace links if someone else is tracing this child. */ list_del_init(&p->ptrace_list); if (p->parent != p->real_parent) list_add(&p->ptrace_list, &p->real_parent->ptrace_children); } else { /* If this child is being traced, then we're the one tracing it * anyway, so let go of it. */ p->ptrace = 0; remove_parent(p); p->parent = p->real_parent; add_parent(p); /* If we'd notified the old parent about this child's death, * also notify the new parent. */ if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 && thread_group_empty(p)) do_notify_parent(p, p->exit_signal); else if (p->state == TASK_TRACED) { /* * If it was at a trace stop, turn it into * a normal stop since it's no longer being * traced. */ ptrace_untrace(p); } } /* * process group orphan check * Case ii: Our child is in a different pgrp * than we are, and it was the only connection * outside, so the child pgrp is now orphaned. */ if ((process_group(p) != process_group(father)) && (p->signal->session == father->signal->session)) { int pgrp = process_group(p); if (will_become_orphaned_pgrp(pgrp, NULL) && has_stopped_jobs(pgrp)) { __kill_pg_info(SIGHUP, SEND_SIG_PRIV, pgrp); __kill_pg_info(SIGCONT, SEND_SIG_PRIV, pgrp); } }} /* * When we die, we re-parent all our children. * Try to give them to another thread in our thread * group, and if no such member exists, give it to * the global child reaper process (ie "init") */static void forget_original_parent(struct task_struct * father, struct list_head *to_release){ struct task_struct *p, *reaper = father; struct list_head *_p, *_n; do { reaper = next_thread(reaper); if (reaper == father) { reaper = child_reaper; break; } } while (reaper->exit_state); /* * There are only two places where our children can be: * * - in our child list * - in our ptraced child list * * Search them and reparent children. */ list_for_each_safe(_p, _n, &father->children) { int ptrace; p = list_entry(_p,struct task_struct,sibling); ptrace = p->ptrace; /* if father isn't the real parent, then ptrace must be enabled */ BUG_ON(father != p->real_parent && !ptrace); if (father == p->real_parent) { /* reparent with a reaper, real father it's us */ choose_new_parent(p, reaper); reparent_thread(p, father, 0); } else { /* reparent ptraced task to its real parent */ __ptrace_unlink (p); if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 && thread_group_empty(p)) do_notify_parent(p, p->exit_signal); } /* * if the ptraced child is a zombie with exit_signal == -1 * we must collect it before we exit, or it will remain * zombie forever since we prevented it from self-reap itself * while it was being traced by us, to be able to see it in wait4. */ if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && p->exit_signal == -1)) list_add(&p->ptrace_list, 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); reparent_thread(p, father, 1); }} /* * Send signals to all our closest relatives so that they know * to properly mourn us.. */static void exit_notify(struct task_struct *tsk){ int state; struct task_struct *t; struct list_head ptrace_dead, *_p, *_n; if (signal_pending(tsk) && !(tsk->signal->flags & SIGNAL_GROUP_EXIT) && !thread_group_empty(tsk)) { /* * This occurs when there was a race between our exit * syscall and a group signal choosing us as the one to * wake up. It could be that we are the only thread * alerted to check for pending signals, but another thread * should be woken now to take the signal since we will not. * 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_tsk(t); if (signal_pending(t)) signal_wake_up(t, 0); } spin_unlock_irq(&tsk->sighand->siglock); read_unlock(&tasklist_lock); } write_lock_irq(&tasklist_lock); /* * This does two things: * * A. Make init inherit all the child processes * B. Check to see if any process groups have become orphaned * as a result of our exiting, and if they have any stopped * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) */ INIT_LIST_HEAD(&ptrace_dead); forget_original_parent(tsk, &ptrace_dead); BUG_ON(!list_empty(&tsk->children)); BUG_ON(!list_empty(&tsk->ptrace_children)); /* * Check to see if any process groups have become orphaned * as a result of our exiting, and if they have any stopped * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) * * Case i: Our father is in a different pgrp than we are * and we were the only connection outside, so our pgrp * is about to become orphaned. */ t = tsk->real_parent; if ((process_group(t) != process_group(tsk)) && (t->signal->session == tsk->signal->session) && will_become_orphaned_pgrp(process_group(tsk), tsk) && has_stopped_jobs(process_group(tsk))) { __kill_pg_info(SIGHUP, SEND_SIG_PRIV, process_group(tsk)); __kill_pg_info(SIGCONT, SEND_SIG_PRIV, process_group(tsk)); } /* Let father know we died * * Thread signals are configurable, but you aren't going to use * that to send signals to arbitary processes. * That stops right now. * * If the parent exec id doesn't match the exec id we saved * when we started then we know the parent has changed security * domain. * * If our self_exec id doesn't match our parent_exec_id then * we have changed execution domain as these two values started * the same after a fork. * */ if (tsk->exit_signal != SIGCHLD && tsk->exit_signal != -1 && ( tsk->parent_exec_id != t->self_exec_id || tsk->self_exec_id != tsk->parent_exec_id) && !capable(CAP_KILL)) tsk->exit_signal = SIGCHLD; /* If something other than our normal parent is ptracing us, then * send it a SIGCHLD instead of honoring exit_signal. exit_signal * only has special meaning to our real parent. */ 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) { do_notify_parent(tsk, SIGCHLD); } state = EXIT_ZOMBIE; if (tsk->exit_signal == -1 && (likely(tsk->ptrace == 0) || unlikely(tsk->parent->signal->flags & SIGNAL_GROUP_EXIT))) state = EXIT_DEAD; tsk->exit_state = state; write_unlock_irq(&tasklist_lock); list_for_each_safe(_p, _n, &ptrace_dead) { list_del_init(_p); t = list_entry(_p,struct task_struct,ptrace_list); release_task(t); } /* If the process is dead, release it - nobody will wait for it */ if (state == EXIT_DEAD) release_task(tsk);} fastcall NORET_TYPE void do_exit(long code){ struct task_struct *tsk = current; int group_dead; profile_task_exit(tsk); WARN_ON(atomic_read(&tsk->fs_excl)); if (unlikely(in_interrupt())) panic("Aiee, killing interrupt handler!"); if (unlikely(!tsk->pid)) panic("Attempted to kill the idle task!"); if (unlikely(tsk == child_reaper)) panic("Attempted to kill init!"); if (unlikely(current->ptrace & PT_TRACE_EXIT)) { current->ptrace_message = code; ptrace_notify((PTRACE_EVENT_EXIT << 8) | SIGTRAP); } /* * We're taking recursive faults here in do_exit. Safest is to just * leave this task alone and wait for reboot. */ if (unlikely(tsk->flags & PF_EXITING)) { printk(KERN_ALERT "Fixing recursive fault but reboot is needed!\n"); if (tsk->io_context) exit_io_context(); set_current_state(TASK_UNINTERRUPTIBLE); schedule(); } tsk->flags |= PF_EXITING; if (unlikely(in_atomic())) printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", current->comm, current->pid, preempt_count()); acct_update_integrals(tsk); if (tsk->mm) { update_hiwater_rss(tsk->mm); update_hiwater_vm(tsk->mm); } group_dead = atomic_dec_and_test(&tsk->signal->live); if (group_dead) { hrtimer_cancel(&tsk->signal->real_timer); exit_itimers(tsk->signal); acct_process(code); } if (unlikely(tsk->robust_list)) exit_robust_list(tsk);#ifdef CONFIG_COMPAT if (unlikely(tsk->compat_robust_list)) compat_exit_robust_list(tsk);#endif if (unlikely(tsk->audit_context)) audit_free(tsk); exit_mm(tsk); exit_sem(tsk); __exit_files(tsk); __exit_fs(tsk); exit_namespace(tsk); exit_thread(); cpuset_exit(tsk); exit_keys(tsk); if (group_dead && tsk->signal->leader) disassociate_ctty(1); module_put(task_thread_info(tsk)->exec_domain->module); if (tsk->binfmt) module_put(tsk->binfmt->module); tsk->exit_code = code; proc_exit_connector(tsk); exit_notify(tsk);#ifdef CONFIG_NUMA mpol_free(tsk->mempolicy); tsk->mempolicy = NULL;#endif /* * If DEBUG_MUTEXES is on, make sure we are holding no locks: */ mutex_debug_check_no_locks_held(tsk); if (tsk->io_context) exit_io_context(); if (tsk->splice_pipe) __free_pipe_info(tsk->splice_pipe); /* PF_DEAD causes final put_task_struct after we schedule. */ preempt_disable(); BUG_ON(tsk->flags & PF_DEAD); tsk->flags |= PF_DEAD; schedule(); BUG(); /* Avoid "noreturn function does return". */ for (;;) ;} EXPORT_SYMBOL_GPL(do_exit); NORET_TYPE void complete_and_exit(struct completion *comp, long code){ if (comp) complete(comp); do_exit(code);} EXPORT_SYMBOL(complete_and_exit); asmlinkage long sys_exit(int error_code){ do_exit((error_code&0xff)<<8);} /* * Take down every thread in the group. This is called by fatal signals * as well as by sys_exit_group (below). */NORET_TYPE voiddo_group_exit(int exit_code){ BUG_ON(exit_code & 0x80); /* core dumps don't get here */ if (current->signal->flags & SIGNAL_GROUP_EXIT) exit_code = current->signal->group_exit_code; else if (!thread_group_empty(current)) { struct signal_struct *const sig = current->signal; struct sighand_struct *const sighand = current->sighand; spin_lock_irq(&sighand->siglock); if (sig->flags & SIGNAL_GROUP_EXIT) /* Another thread got here before we took the lock. */ exit_code = sig->group_exit_code; else { sig->group_exit_code = exit_code; zap_other_threads(current); } spin_unlock_irq(&sighand->siglock); } do_exit(exit_code); /* NOTREACHED */} /*Lines 501–1000 of 1639. Previous lines Load more
tsk->files = NULL; task_unlock(tsk); put_files_struct(files); } } void exit_files(struct task_struct *tsk) { __exit_files(tsk); } static inline void __put_fs_struct(struct fs_struct *fs) { /* No need to hold fs->lock if we are killing it */ if (atomic_dec_and_test(&fs->count)) { dput(fs->root); mntput(fs->rootmnt); dput(fs->pwd); mntput(fs->pwdmnt); if (fs->altroot) { dput(fs->altroot); mntput(fs->altrootmnt); } kmem_cache_free(fs_cachep, fs); } } void put_fs_struct(struct fs_struct *fs) { __put_fs_struct(fs); } static inline void __exit_fs(struct task_struct *tsk) { struct fs_struct * fs = tsk->fs; if (fs) { task_lock(tsk); tsk->fs = NULL; task_unlock(tsk); __put_fs_struct(fs); } } void exit_fs(struct task_struct *tsk) { __exit_fs(tsk); } EXPORT_SYMBOL_GPL(exit_fs); /* * Turn us into a lazy TLB process if we * aren't already.. */ static void exit_mm(struct task_struct * tsk) { struct mm_struct *mm = tsk->mm; mm_release(tsk, mm); if (!mm) return; /* * Serialize with any possible pending coredump. * We must hold mmap_sem around checking core_waiters * and clearing tsk->mm. The core-inducing thread * will increment core_waiters for each thread in the * group with ->mm != NULL. */ down_read(&mm->mmap_sem); if (mm->core_waiters) { up_read(&mm->mmap_sem); down_write(&mm->mmap_sem); if (!--mm->core_waiters) complete(mm->core_startup_done); up_write(&mm->mmap_sem); wait_for_completion(&mm->core_done); down_read(&mm->mmap_sem); } atomic_inc(&mm->mm_count); if (mm != tsk->active_mm) BUG(); /* more a memory barrier than a real lock */ task_lock(tsk); tsk->mm = NULL; up_read(&mm->mmap_sem); enter_lazy_tlb(mm, current); task_unlock(tsk); mmput(mm); } static inline void choose_new_parent(task_t *p, task_t *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(task_t *p, task_t *father, int traced) { /* We don't want people slaying init. */ if (p->exit_signal != -1) p->exit_signal = SIGCHLD; if (p->pdeath_signal) /* We already hold the tasklist_lock here. */ group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p); /* Move the child from its dying parent to the new one. */ if (unlikely(traced)) { /* Preserve ptrace links if someone else is tracing this child. */ list_del_init(&p->ptrace_list); if (p->parent != p->real_parent) list_add(&p->ptrace_list, &p->real_parent->ptrace_children); } else { /* If this child is being traced, then we're the one tracing it * anyway, so let go of it. */ p->ptrace = 0; remove_parent(p); p->parent = p->real_parent; add_parent(p); /* If we'd notified the old parent about this child's death, * also notify the new parent. */ if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 && thread_group_empty(p)) do_notify_parent(p, p->exit_signal); else if (p->state == TASK_TRACED) { /* * If it was at a trace stop, turn it into * a normal stop since it's no longer being * traced. */ ptrace_untrace(p); } } /* * process group orphan check * Case ii: Our child is in a different pgrp * than we are, and it was the only connection * outside, so the child pgrp is now orphaned. */ if ((process_group(p) != process_group(father)) && (p->signal->session == father->signal->session)) { int pgrp = process_group(p); if (will_become_orphaned_pgrp(pgrp, NULL) && has_stopped_jobs(pgrp)) { __kill_pg_info(SIGHUP, SEND_SIG_PRIV, pgrp); __kill_pg_info(SIGCONT, SEND_SIG_PRIV, pgrp); } } } /* * When we die, we re-parent all our children. * Try to give them to another thread in our thread * group, and if no such member exists, give it to * the global child reaper process (ie "init") */ static void forget_original_parent(struct task_struct * father, struct list_head *to_release) { struct task_struct *p, *reaper = father; struct list_head *_p, *_n; do { reaper = next_thread(reaper); if (reaper == father) { reaper = child_reaper; break; } } while (reaper->exit_state); /* * There are only two places where our children can be: * * - in our child list * - in our ptraced child list * * Search them and reparent children. */ list_for_each_safe(_p, _n, &father->children) { int ptrace; p = list_entry(_p,struct task_struct,sibling); ptrace = p->ptrace; /* if father isn't the real parent, then ptrace must be enabled */ BUG_ON(father != p->real_parent && !ptrace); if (father == p->real_parent) { /* reparent with a reaper, real father it's us */ choose_new_parent(p, reaper); reparent_thread(p, father, 0); } else { /* reparent ptraced task to its real parent */ __ptrace_unlink (p); if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 && thread_group_empty(p)) do_notify_parent(p, p->exit_signal); } /* * if the ptraced child is a zombie with exit_signal == -1 * we must collect it before we exit, or it will remain * zombie forever since we prevented it from self-reap itself * while it was being traced by us, to be able to see it in wait4. */ if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && p->exit_signal == -1)) list_add(&p->ptrace_list, 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); reparent_thread(p, father, 1); } } /* * Send signals to all our closest relatives so that they know * to properly mourn us.. */ static void exit_notify(struct task_struct *tsk) { int state; struct task_struct *t; struct list_head ptrace_dead, *_p, *_n; if (signal_pending(tsk) && !(tsk->signal->flags & SIGNAL_GROUP_EXIT) && !thread_group_empty(tsk)) { /* * This occurs when there was a race between our exit * syscall and a group signal choosing us as the one to * wake up. It could be that we are the only thread * alerted to check for pending signals, but another thread * should be woken now to take the signal since we will not. * 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_tsk(t); if (signal_pending(t)) signal_wake_up(t, 0); } spin_unlock_irq(&tsk->sighand->siglock); read_unlock(&tasklist_lock); } write_lock_irq(&tasklist_lock); /* * This does two things: * * A. Make init inherit all the child processes * B. Check to see if any process groups have become orphaned * as a result of our exiting, and if they have any stopped * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) */ INIT_LIST_HEAD(&ptrace_dead); forget_original_parent(tsk, &ptrace_dead); BUG_ON(!list_empty(&tsk->children)); BUG_ON(!list_empty(&tsk->ptrace_children)); /* * Check to see if any process groups have become orphaned * as a result of our exiting, and if they have any stopped * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) * * Case i: Our father is in a different pgrp than we are * and we were the only connection outside, so our pgrp * is about to become orphaned. */ t = tsk->real_parent; if ((process_group(t) != process_group(tsk)) && (t->signal->session == tsk->signal->session) && will_become_orphaned_pgrp(process_group(tsk), tsk) && has_stopped_jobs(process_group(tsk))) { __kill_pg_info(SIGHUP, SEND_SIG_PRIV, process_group(tsk)); __kill_pg_info(SIGCONT, SEND_SIG_PRIV, process_group(tsk)); } /* Let father know we died * * Thread signals are configurable, but you aren't going to use * that to send signals to arbitary processes. * That stops right now. * * If the parent exec id doesn't match the exec id we saved * when we started then we know the parent has changed security * domain. * * If our self_exec id doesn't match our parent_exec_id then * we have changed execution domain as these two values started * the same after a fork. * */ if (tsk->exit_signal != SIGCHLD && tsk->exit_signal != -1 && ( tsk->parent_exec_id != t->self_exec_id || tsk->self_exec_id != tsk->parent_exec_id) && !capable(CAP_KILL)) tsk->exit_signal = SIGCHLD; /* If something other than our normal parent is ptracing us, then * send it a SIGCHLD instead of honoring exit_signal. exit_signal * only has special meaning to our real parent. */ 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) { do_notify_parent(tsk, SIGCHLD); } state = EXIT_ZOMBIE; if (tsk->exit_signal == -1 && (likely(tsk->ptrace == 0) || unlikely(tsk->parent->signal->flags & SIGNAL_GROUP_EXIT))) state = EXIT_DEAD; tsk->exit_state = state; write_unlock_irq(&tasklist_lock); list_for_each_safe(_p, _n, &ptrace_dead) { list_del_init(_p); t = list_entry(_p,struct task_struct,ptrace_list); release_task(t); } /* If the process is dead, release it - nobody will wait for it */ if (state == EXIT_DEAD) release_task(tsk); } fastcall NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; int group_dead; profile_task_exit(tsk); WARN_ON(atomic_read(&tsk->fs_excl)); if (unlikely(in_interrupt())) panic("Aiee, killing interrupt handler!"); if (unlikely(!tsk->pid)) panic("Attempted to kill the idle task!"); if (unlikely(tsk == child_reaper)) panic("Attempted to kill init!"); if (unlikely(current->ptrace & PT_TRACE_EXIT)) { current->ptrace_message = code; ptrace_notify((PTRACE_EVENT_EXIT << 8) | SIGTRAP); } /* * We're taking recursive faults here in do_exit. Safest is to just * leave this task alone and wait for reboot. */ if (unlikely(tsk->flags & PF_EXITING)) { printk(KERN_ALERT "Fixing recursive fault but reboot is needed!\n"); if (tsk->io_context) exit_io_context(); set_current_state(TASK_UNINTERRUPTIBLE); schedule(); } tsk->flags |= PF_EXITING; if (unlikely(in_atomic())) printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", current->comm, current->pid, preempt_count()); acct_update_integrals(tsk); if (tsk->mm) { update_hiwater_rss(tsk->mm); update_hiwater_vm(tsk->mm); } group_dead = atomic_dec_and_test(&tsk->signal->live); if (group_dead) { hrtimer_cancel(&tsk->signal->real_timer); exit_itimers(tsk->signal); acct_process(code); } if (unlikely(tsk->robust_list)) exit_robust_list(tsk); #ifdef CONFIG_COMPAT if (unlikely(tsk->compat_robust_list)) compat_exit_robust_list(tsk); #endif if (unlikely(tsk->audit_context)) audit_free(tsk); exit_mm(tsk); exit_sem(tsk); __exit_files(tsk); __exit_fs(tsk); exit_namespace(tsk); exit_thread(); cpuset_exit(tsk); exit_keys(tsk); if (group_dead && tsk->signal->leader) disassociate_ctty(1); module_put(task_thread_info(tsk)->exec_domain->module); if (tsk->binfmt) module_put(tsk->binfmt->module); tsk->exit_code = code; proc_exit_connector(tsk); exit_notify(tsk); #ifdef CONFIG_NUMA mpol_free(tsk->mempolicy); tsk->mempolicy = NULL; #endif /* * If DEBUG_MUTEXES is on, make sure we are holding no locks: */ mutex_debug_check_no_locks_held(tsk); if (tsk->io_context) exit_io_context(); if (tsk->splice_pipe) __free_pipe_info(tsk->splice_pipe); /* PF_DEAD causes final put_task_struct after we schedule. */ preempt_disable(); BUG_ON(tsk->flags & PF_DEAD); tsk->flags |= PF_DEAD; schedule(); BUG(); /* Avoid "noreturn function does return". */ for (;;) ; } EXPORT_SYMBOL_GPL(do_exit); NORET_TYPE void complete_and_exit(struct completion *comp, long code) { if (comp) complete(comp); do_exit(code); } EXPORT_SYMBOL(complete_and_exit); asmlinkage long sys_exit(int error_code) { do_exit((error_code&0xff)<<8); } /* * Take down every thread in the group. This is called by fatal signals * as well as by sys_exit_group (below). */ NORET_TYPE void do_group_exit(int exit_code) { BUG_ON(exit_code & 0x80); /* core dumps don't get here */ if (current->signal->flags & SIGNAL_GROUP_EXIT) exit_code = current->signal->group_exit_code; else if (!thread_group_empty(current)) { struct signal_struct *const sig = current->signal; struct sighand_struct *const sighand = current->sighand; spin_lock_irq(&sighand->siglock); if (sig->flags & SIGNAL_GROUP_EXIT) /* Another thread got here before we took the lock. */ exit_code = sig->group_exit_code; else { sig->group_exit_code = exit_code; zap_other_threads(current); } spin_unlock_irq(&sighand->siglock); } do_exit(exit_code); /* NOTREACHED */ } /*