cregit-Linux how code gets into the kernel

Release 4.15 kernel/exit.c

Directory: kernel
/*
 *  linux/kernel/exit.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/sched/autogroup.h>
#include <linux/sched/mm.h>
#include <linux/sched/stat.h>
#include <linux/sched/task.h>
#include <linux/sched/task_stack.h>
#include <linux/sched/cputime.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/capability.h>
#include <linux/completion.h>
#include <linux/personality.h>
#include <linux/tty.h>
#include <linux/iocontext.h>
#include <linux/key.h>
#include <linux/cpu.h>
#include <linux/acct.h>
#include <linux/tsacct_kern.h>
#include <linux/file.h>
#include <linux/fdtable.h>
#include <linux/freezer.h>
#include <linux/binfmts.h>
#include <linux/nsproxy.h>
#include <linux/pid_namespace.h>
#include <linux/ptrace.h>
#include <linux/profile.h>
#include <linux/mount.h>
#include <linux/proc_fs.h>
#include <linux/kthread.h>
#include <linux/mempolicy.h>
#include <linux/taskstats_kern.h>
#include <linux/delayacct.h>
#include <linux/cgroup.h>
#include <linux/syscalls.h>
#include <linux/signal.h>
#include <linux/posix-timers.h>
#include <linux/cn_proc.h>
#include <linux/mutex.h>
#include <linux/futex.h>
#include <linux/pipe_fs_i.h>
#include <linux/audit.h> /* for audit_free() */
#include <linux/resource.h>
#include <linux/blkdev.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/tracehook.h>
#include <linux/fs_struct.h>
#include <linux/init_task.h>
#include <linux/perf_event.h>
#include <trace/events/sched.h>
#include <linux/hw_breakpoint.h>
#include <linux/oom.h>
#include <linux/writeback.h>
#include <linux/shm.h>
#include <linux/kcov.h>
#include <linux/random.h>
#include <linux/rcuwait.h>
#include <linux/compat.h>

#include <linux/uaccess.h>
#include <asm/unistd.h>
#include <asm/pgtable.h>
#include <asm/mmu_context.h>


static void __unhash_process(struct task_struct *p, bool group_dead) { nr_threads--; detach_pid(p, PIDTYPE_PID); if (group_dead) { detach_pid(p, PIDTYPE_PGID); detach_pid(p, PIDTYPE_SID); list_del_rcu(&p->tasks); list_del_init(&p->sibling); __this_cpu_dec(process_counts); } list_del_rcu(&p->thread_group); list_del_rcu(&p->thread_node); }

Contributors

PersonTokensPropCommitsCommitProp
Oleg Nesterov4251.85%650.00%
Ingo Molnar1720.99%18.33%
Al Viro1518.52%18.33%
Andrew Morton56.17%216.67%
Christoph Lameter11.23%18.33%
Eric W. Biedermann11.23%18.33%
Total81100.00%12100.00%

/* * This function expects the tasklist_lock write-locked. */
static void __exit_signal(struct task_struct *tsk) { struct signal_struct *sig = tsk->signal; bool group_dead = thread_group_leader(tsk); struct sighand_struct *sighand; struct tty_struct *uninitialized_var(tty); u64 utime, stime; sighand = rcu_dereference_check(tsk->sighand, lockdep_tasklist_lock_is_held()); spin_lock(&sighand->siglock); #ifdef CONFIG_POSIX_TIMERS posix_cpu_timers_exit(tsk); if (group_dead) { posix_cpu_timers_exit_group(tsk); } else { /* * This can only happen if the caller is de_thread(). * FIXME: this is the temporary hack, we should teach * posix-cpu-timers to handle this case correctly. */ if (unlikely(has_group_leader_pid(tsk))) posix_cpu_timers_exit_group(tsk); } #endif if (group_dead) { tty = sig->tty; sig->tty = NULL; } else { /* * If there is any task waiting for the group exit * then notify it: */ if (sig->notify_count > 0 && !--sig->notify_count) wake_up_process(sig->group_exit_task); if (tsk == sig->curr_target) sig->curr_target = next_thread(tsk); } add_device_randomness((const void*) &tsk->se.sum_exec_runtime, sizeof(unsigned long long)); /* * Accumulate here the counters for all threads as they die. We could * skip the group leader because it is the last user of signal_struct, * but we want to avoid the race with thread_group_cputime() which can * see the empty ->thread_head list. */ task_cputime(tsk, &utime, &stime); write_seqlock(&sig->stats_lock); sig->utime += utime; sig->stime += stime; sig->gtime += task_gtime(tsk); sig->min_flt += tsk->min_flt; sig->maj_flt += tsk->maj_flt; sig->nvcsw += tsk->nvcsw; sig->nivcsw += tsk->nivcsw; sig->inblock += task_io_get_inblock(tsk); sig->oublock += task_io_get_oublock(tsk); task_io_accounting_add(&sig->ioac, &tsk->ioac); sig->sum_sched_runtime += tsk->se.sum_exec_runtime; sig->nr_threads--; __unhash_process(tsk, group_dead); write_sequnlock(&sig->stats_lock); /* * Do this under ->siglock, we can race with another thread * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals. */ flush_sigqueue(&tsk->pending); tsk->sighand = NULL; spin_unlock(&sighand->siglock); __cleanup_sighand(sighand); clear_tsk_thread_flag(tsk, TIF_SIGPENDING); if (group_dead) { flush_sigqueue(&sig->shared_pending); tty_kref_put(tty); } }

Contributors

PersonTokensPropCommitsCommitProp
Oleg Nesterov23161.44%1244.44%
Nico Pitre4812.77%27.41%
Frédéric Weisbecker195.05%27.41%
Eric Dumazet174.52%13.70%
Peter Zijlstra174.52%13.70%
Rik Van Riel174.52%27.41%
Andrea Righi133.46%27.41%
Laurent Vivier51.33%13.70%
Paul E. McKenney41.06%27.41%
Martin Schwidefsky30.80%13.70%
Hidetoshi Seto20.53%13.70%
Total376100.00%27100.00%


static void delayed_put_task_struct(struct rcu_head *rhp) { struct task_struct *tsk = container_of(rhp, struct task_struct, rcu); perf_event_delayed_put(tsk); trace_sched_process_free(tsk); put_task_struct(tsk); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann2253.66%125.00%
Mathieu Desnoyers1434.15%125.00%
Ingo Molnar49.76%125.00%
Peter Zijlstra12.44%125.00%
Total41100.00%4100.00%


void release_task(struct task_struct *p) { struct task_struct *leader; int zap_leader; repeat: /* don't need to get the RCU readlock here - the process is dead and * can't be modifying its own credentials. But shut RCU-lockdep up */ rcu_read_lock(); atomic_dec(&__task_cred(p)->user->processes); rcu_read_unlock(); proc_flush_task(p); write_lock_irq(&tasklist_lock); ptrace_release_task(p); __exit_signal(p); /* * If we are the last non-leader member of the thread * 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->exit_state == EXIT_ZOMBIE) { /* * 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. */ zap_leader = do_notify_parent(leader, leader->exit_signal); if (zap_leader) leader->exit_state = EXIT_DEAD; } write_unlock_irq(&tasklist_lock); release_thread(p); call_rcu(&p->rcu, delayed_put_task_struct); p = leader; if (unlikely(zap_leader)) goto repeat; }

Contributors

PersonTokensPropCommitsCommitProp
Ingo Molnar5839.19%626.09%
Linus Torvalds2818.92%28.70%
Linus Torvalds (pre-git)2416.22%730.43%
Roland McGrath106.76%14.35%
Paul E. McKenney74.73%14.35%
Eric W. Biedermann64.05%14.35%
Pavel Emelyanov53.38%14.35%
David Howells32.03%14.35%
Andrew Morton32.03%14.35%
Oleg Nesterov32.03%14.35%
Tejun Heo10.68%14.35%
Total148100.00%23100.00%

/* * Note that if this function returns a valid task_struct pointer (!NULL) * task->usage must remain >0 for the duration of the RCU critical section. */
struct task_struct *task_rcu_dereference(struct task_struct **ptask) { struct sighand_struct *sighand; struct task_struct *task; /* * We need to verify that release_task() was not called and thus * delayed_put_task_struct() can't run and drop the last reference * before rcu_read_unlock(). We check task->sighand != NULL, * but we can read the already freed and reused memory. */ retry: task = rcu_dereference(*ptask); if (!task) return NULL; probe_kernel_address(&task->sighand, sighand); /* * Pairs with atomic_dec_and_test() in put_task_struct(). If this task * was already freed we can not miss the preceding update of this * pointer. */ smp_rmb(); if (unlikely(task != READ_ONCE(*ptask))) goto retry; /* * We've re-checked that "task == *ptask", now we have two different * cases: * * 1. This is actually the same task/task_struct. In this case * sighand != NULL tells us it is still alive. * * 2. This is another task which got the same memory for task_struct. * We can't know this of course, and we can not trust * sighand != NULL. * * In this case we actually return a random value, but this is * correct. * * If we return NULL - we can pretend that we actually noticed that * *ptask was updated when the previous task has exited. Or pretend * that probe_slab_address(&sighand) reads NULL. * * If we return the new task (because sighand is not NULL for any * reason) - this is fine too. This (new) task can't go away before * another gp pass. * * And note: We could even eliminate the false positive if re-read * task->sighand once again to avoid the falsely NULL. But this case * is very unlikely so we don't care. */ if (!sighand) return NULL; return task; }

Contributors

PersonTokensPropCommitsCommitProp
Oleg Nesterov84100.00%1100.00%
Total84100.00%1100.00%


void rcuwait_wake_up(struct rcuwait *w) { struct task_struct *task; rcu_read_lock(); /* * Order condition vs @task, such that everything prior to the load * of @task is visible. This is the condition as to why the user called * rcuwait_trywake() in the first place. Pairs with set_current_state() * barrier (A) in rcuwait_wait_event(). * * WAIT WAKE * [S] tsk = current [S] cond = true * MB (A) MB (B) * [L] cond [L] tsk */ smp_rmb(); /* (B) */ /* * Avoid using task_rcu_dereference() magic as long as we are careful, * see comment in rcuwait_wait_event() regarding ->exit_state. */ task = rcu_dereference(w->task); if (task) wake_up_process(task); rcu_read_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Davidlohr Bueso A45100.00%1100.00%
Total45100.00%1100.00%

/* * Determine if a process group is "orphaned", according to the POSIX * definition in 2.2.2.52. Orphaned process groups are not to be affected * by terminal-generated stop signals. Newly orphaned process groups are * to receive a SIGHUP and a SIGCONT. * * "I ask you, have you ever known what it is to be an orphan?" */
static int will_become_orphaned_pgrp(struct pid *pgrp, struct task_struct *ignored_task) { struct task_struct *p; do_each_pid_task(pgrp, PIDTYPE_PGID, p) { if ((p == ignored_task) || (p->exit_state && thread_group_empty(p)) || is_global_init(p->real_parent)) continue; if (task_pgrp(p->real_parent) != pgrp && task_session(p->real_parent) == task_session(p)) return 0; } while_each_pid_task(pgrp, PIDTYPE_PGID, p); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4546.88%423.53%
Oleg Nesterov1212.50%15.88%
Ingo Molnar1010.42%423.53%
Eric W. Biedermann88.33%15.88%
Kirill Korotaev88.33%15.88%
Cédric Le Goater44.17%15.88%
Daniel Jacobowitz33.12%15.88%
Andrew Morton33.12%211.76%
Sukadev Bhattiprolu22.08%15.88%
Serge E. Hallyn11.04%15.88%
Total96100.00%17100.00%


int is_current_pgrp_orphaned(void) { int retval; read_lock(&tasklist_lock); retval = will_become_orphaned_pgrp(task_pgrp(current), NULL); read_unlock(&tasklist_lock); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Ingo Molnar2054.05%116.67%
Linus Torvalds (pre-git)924.32%233.33%
Eric W. Biedermann616.22%233.33%
Andrew Morton25.41%116.67%
Total37100.00%6100.00%


static bool has_stopped_jobs(struct pid *pgrp) { struct task_struct *p; do_each_pid_task(pgrp, PIDTYPE_PGID, p) { if (p->signal->flags & SIGNAL_STOP_STOPPED) return true; } while_each_pid_task(pgrp, PIDTYPE_PGID, p); return false; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1937.25%225.00%
Oleg Nesterov1121.57%112.50%
Kirill Korotaev815.69%112.50%
Ingo Molnar713.73%225.00%
Eric W. Biedermann59.80%112.50%
Andrew Morton11.96%112.50%
Total51100.00%8100.00%

/* * 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) */
static void kill_orphaned_pgrp(struct task_struct *tsk, struct task_struct *parent) { struct pid *pgrp = task_pgrp(tsk); struct task_struct *ignored_task = tsk; if (!parent) /* exit: our father is in a different pgrp than * we are and we were the only connection outside. */ parent = tsk->real_parent; else /* reparent: our child is in a different pgrp than * we are, and it was the only connection outside. */ ignored_task = NULL; if (task_pgrp(parent) != pgrp && task_session(parent) == task_session(tsk) && will_become_orphaned_pgrp(pgrp, ignored_task) && has_stopped_jobs(pgrp)) { __kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp); __kill_pgrp_info(SIGCONT, SEND_SIG_PRIV, pgrp); } }

Contributors

PersonTokensPropCommitsCommitProp
Oleg Nesterov10199.02%150.00%
Ionut Alexa10.98%150.00%
Total102100.00%2100.00%

#ifdef CONFIG_MEMCG /* * A task is exiting. If it owned this mm, find a new owner for the mm. */
void mm_update_next_owner(struct mm_struct *mm) { struct task_struct *c, *g, *p = current; retry: /* * If the exiting or execing task is not the owner, it's * someone else's problem. */ if (mm->owner != p) return; /* * The current owner is exiting/execing and there are no other * candidates. Do not leave the mm pointing to a possibly * freed task structure. */ if (atomic_read(&mm->mm_users) <= 1) { mm->owner = NULL; return; } read_lock(&tasklist_lock); /* * Search in the children */ list_for_each_entry(c, &p->children, sibling) { if (c->mm == mm) goto assign_new_owner; } /* * Search in the siblings */ list_for_each_entry(c, &p->real_parent->children, sibling) { if (c->mm == mm) goto assign_new_owner; } /* * Search through everything else, we should not get here often. */ for_each_process(g) { if (g->flags & PF_KTHREAD) continue; for_each_thread(g, c) { if (c->mm == mm) goto assign_new_owner; if (c->mm) break; } } read_unlock(&tasklist_lock); /* * We found no owner yet mm_users > 1: this implies that we are * most likely racing with swapoff (try_to_unuse()) or /proc or * ptrace or page migration (get_task_mm()). Mark owner as NULL. */ mm->owner = NULL; return; assign_new_owner: BUG_ON(c == p); get_task_struct(c); /* * The task_lock protects c->mm from changing. * We always want mm->owner->mm == mm */ task_lock(c); /* * Delay read_unlock() till we have the task_lock() * to ensure that c does not slip away underneath us */ read_unlock(&tasklist_lock); if (c->mm != mm) { task_unlock(c); put_task_struct(c); goto retry; } mm->owner = c; task_unlock(c); put_task_struct(c); }

Contributors

PersonTokensPropCommitsCommitProp
Balbir Singh17074.24%228.57%
Oleg Nesterov2711.79%342.86%
Kamezawa Hiroyuki2510.92%114.29%
Hugh Dickins73.06%114.29%
Total229100.00%7100.00%

#endif /* CONFIG_MEMCG */ /* * Turn us into a lazy TLB process if we * aren't already.. */
static void exit_mm(void) { struct mm_struct *mm = current->mm; struct core_state *core_state; mm_release(current, mm); if (!mm) return; sync_mm_rss(mm); /* * Serialize with any possible pending coredump. * We must hold mmap_sem around checking core_state * and clearing tsk->mm. The core-inducing thread * will increment ->nr_threads for each thread in the * group with ->mm != NULL. */ down_read(&mm->mmap_sem); core_state = mm->core_state; if (core_state) { struct core_thread self; up_read(&mm->mmap_sem); self.task = current; self.next = xchg(&core_state->dumper.next, &self); /* * Implies mb(), the result of xchg() must be visible * to core_state->dumper. */ if (atomic_dec_and_test(&core_state->nr_threads)) complete(&core_state->startup); for (;;) { set_current_state(TASK_UNINTERRUPTIBLE); if (!self.task) /* see coredump_finish() */ break; freezable_schedule(); } __set_current_state(TASK_RUNNING); down_read(&mm->mmap_sem); } mmgrab(mm); BUG_ON(mm != current->active_mm); /* more a memory barrier than a real lock */ task_lock(current); current->mm = NULL; up_read(&mm->mmap_sem); enter_lazy_tlb(mm, current); task_unlock(current); mm_update_next_owner(mm); mmput(mm); if (test_thread_flag(TIF_MEMDIE)) exit_oom_victim(); }

Contributors

PersonTokensPropCommitsCommitProp
Oleg Nesterov6529.82%616.67%
Linus Torvalds (pre-git)4922.48%1336.11%
Andrew Morton3214.68%12.78%
Ingo Molnar2611.93%25.56%
Davidlohr Bueso A104.59%25.56%
Michal Hocko73.21%12.78%
Linus Torvalds62.75%12.78%
Konstantin Khlebnikov52.29%12.78%
Balbir Singh52.29%12.78%
Robert Love41.83%12.78%
Eric Sesterhenn / Snakebyte31.38%12.78%
Mandeep Singh Baines10.46%12.78%
Vegard Nossum10.46%12.78%
Tetsuo Handa10.46%12.78%
Adrian Bunk10.46%12.78%
David Rientjes10.46%12.78%
Johannes Weiner10.46%12.78%
Total218100.00%36100.00%


static struct task_struct *find_alive_thread(struct task_struct *p) { struct task_struct *t; for_each_thread(p, t) { if (!(t->flags & PF_EXITING)) return t; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Oleg Nesterov43100.00%1100.00%
Total43100.00%1100.00%


static struct task_struct *find_child_reaper(struct task_struct *father) __releases(&tasklist_lock

Contributors

PersonTokensPropCommitsCommitProp
Oleg Nesterov1178.57%266.67%
Namhyung Kim321.43%133.33%
Total14100.00%3100.00%

) __acquires(&tasklist_lock) { struct pid_namespace *pid_ns = task_active_pid_ns(father); struct task_struct *reaper = pid_ns->child_reaper; if (likely(reaper != father)) return reaper; reaper = find_alive_thread(father); if (reaper) { pid_ns->child_reaper = reaper; return reaper; } write_unlock_irq(&tasklist_lock); if (unlikely(pid_ns == &init_pid_ns)) { panic("Attempted to kill init! exitcode=0x%08x\n", father->signal->group_exit_code ?: father->exit_code); } zap_pid_ns_processes(pid_ns); write_lock_irq(&tasklist_lock); return father; } /* * When we die, we re-parent all our children, and try to: * 1. give them to another thread in our thread group, if such a member exists * 2. give it to the first ancestor process which prctl'd itself as a * child_subreaper for its children (like a service manager) * 3. give it to the init process (PID 1) in our pid namespace */
static struct task_struct *find_new_reaper(struct task_struct *father, struct task_struct *child_reaper) { struct task_struct *thread, *reaper; thread = find_alive_thread(father); if (thread) return thread; if (father->signal->has_child_subreaper) { unsigned int ns_level = task_pid(father)->level; /* * Find the first ->is_child_subreaper ancestor in our pid_ns. * We can't check reaper != child_reaper to ensure we do not * cross the namespaces, the exiting parent could be injected * by setns() + fork(). * We check pid->level, this is slightly more efficient than * task_active_pid_ns(reaper) != task_active_pid_ns(father). */ for (reaper = father->real_parent; task_pid(reaper)->level == ns_level; reaper = reaper->real_parent) { if (reaper == &init_task) break; if (!reaper->signal->is_child_subreaper) continue; thread = find_alive_thread(reaper); if (thread) return thread; } } return child_reaper; }

Contributors

PersonTokensPropCommitsCommitProp
Oleg Nesterov7460.66%787.50%
Lennart Poettering4839.34%112.50%
Total122100.00%8100.00%

/* * Any that need to be release_task'd are put on the @dead list. */
static void reparent_leader(struct task_struct *father, struct task_struct *p, struct list_head *dead) { if (unlikely(p->exit_state == EXIT_DEAD)) return; /* We don't want people slaying init. */ p->exit_signal = SIGCHLD; /* If it has exited notify the new parent about this child's death. */ if (!p->ptrace && p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) { if (do_notify_parent(p, p->exit_signal)) { p->exit_state = EXIT_DEAD; list_add(&p->ptrace_entry, dead); } } kill_orphaned_pgrp(p, father); }

Contributors

PersonTokensPropCommitsCommitProp
Oleg Nesterov9597.94%787.50%
Tejun Heo22.06%112.50%
Total97100.00%8100.00%

/* * 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) */
static void forget_original_parent(struct task_struct *father, struct list_head *dead) { struct task_struct *p, *t, *reaper; if (unlikely(!list_empty(&father->ptraced))) exit_ptrace(father, dead); /* Can drop and reacquire tasklist_lock */ reaper = find_child_reaper(father); if (list_empty(&father->children)) return; reaper = find_new_reaper(father, reaper); list_for_each_entry(p, &father->children, sibling) { for_each_thread(p, t) { t->real_parent = reaper; 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); } /* * 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); } list_splice_tail_init(&father->children, &reaper->children); }

Contributors

PersonTokensPropCommitsCommitProp
Oleg Nesterov14075.27%1376.47%
Daniel Jacobowitz2714.52%15.88%
Roland McGrath158.06%15.88%
Matthias Kaehlcke21.08%15.88%
Tejun Heo21.08%15.88%
Total186100.00%17100.00%

/* * Send signals to all our closest relatives so that they know * to properly mourn us.. */
static void exit_notify(struct task_struct *tsk, int group_dead) { bool autoreap; struct task_struct *p, *n; LIST_HEAD(dead); write_lock_irq(&tasklist_lock); forget_original_parent(tsk, &dead); if (group_dead) kill_orphaned_pgrp(tsk->group_leader, NULL); if (unlikely(tsk->ptrace)) { int sig = thread_group_leader(tsk) && thread_group_empty(tsk) && !ptrace_reparented(tsk) ? tsk->exit_signal : SIGCHLD; autoreap = do_notify_parent(tsk, sig); } else if (thread_group_leader(tsk)) { autoreap = thread_group_empty(tsk) && do_notify_parent(tsk, tsk->exit_signal); } else { autoreap = true; } tsk->exit_state = autoreap ? EXIT_DEAD : EXIT_ZOMBIE; if (tsk->exit_state == EXIT_DEAD) list_add(&tsk->ptrace_entry, &dead); /* mt-exec, de_thread() is waiting for group leader */ if (unlikely(tsk->signal->notify_count < 0)) wake_up_process(tsk->signal->group_exit_task); write_unlock_irq(&tasklist_lock); list_for_each_entry_safe(p, n, &dead, ptrace_entry) { list_del_init(&p->ptrace_entry); release_task(p); } }

Contributors

PersonTokensPropCommitsCommitProp
Oleg Nesterov16073.39%1038.46%
Ingo Molnar146.42%415.38%
Roland McGrath115.05%311.54%
Andrew Morton73.21%13.85%
Linus Torvalds (pre-git)62.75%27.69%
Linus Torvalds62.75%13.85%
Daniel Jacobowitz52.29%27.69%
Andrea Arcangeli41.83%13.85%
Steve VanDeBogart31.38%13.85%
Eric W. Biedermann20.92%13.85%
Total218100.00%26100.00%

#ifdef CONFIG_DEBUG_STACK_USAGE
static void check_stack_usage(void) { static DEFINE_SPINLOCK(low_water_lock); static int lowest_to_date = THREAD_SIZE; unsigned long free; free = stack_not_used(current); if (free >= lowest_to_date) return; spin_lock(&low_water_lock); if (free < lowest_to_date) { pr_info("%s (%d) used greatest stack depth: %lu bytes left\n", current->comm, task_pid_nr(current), free); lowest_to_date = free; } spin_unlock(&low_water_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike7089.74%120.00%
Tim Bird56.41%120.00%
Anton Blanchard11.28%120.00%
Ionut Alexa11.28%120.00%
Eric Sandeen11.28%120.00%
Total78100.00%5100.00%

#else
static inline void check_stack_usage(void) {}

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike8100.00%1100.00%
Total8100.00%1100.00%

#endif
void __noreturn do_exit(long code) { struct task_struct *tsk = current; int group_dead; profile_task_exit(tsk); kcov_task_exit(tsk); WARN_ON(blk_needs_flush_plug(tsk)); if (unlikely(in_interrupt())) panic("Aiee, killing interrupt handler!"); if (unlikely(!tsk->pid)) panic("Attempted to kill the idle task!"); /* * If do_exit is called because this processes oopsed, it's possible * that get_fs() was left as KERNEL_DS, so reset it to USER_DS before * continuing. Amongst other possible reasons, this is to prevent * mm_release()->clear_child_tid() from writing to a user-controlled * kernel address. */ set_fs(USER_DS); ptrace_event(PTRACE_EVENT_EXIT, code); validate_creds_for_do_exit(tsk); /* * 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)) { pr_alert("Fixing recursive fault but reboot is needed!\n"); /* * We can do this unlocked here. The futex code uses * this flag just to verify whether the pi state * cleanup has been done or not. In the worst case it * loops once more. We pretend that the cleanup was * done as there is no way to return. Either the * OWNER_DIED bit is set by now or we push the blocked * task into the wait for ever nirwana as well. */ tsk->flags |= PF_EXITPIDONE; set_current_state(TASK_UNINTERRUPTIBLE); schedule(); } exit_signals(tsk); /* sets PF_EXITING */ /* * Ensure that all new tsk->pi_lock acquisitions must observe * PF_EXITING. Serializes against futex.c:attach_to_pi_owner(). */