Release 4.15 kernel/exit.c
/*
* 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
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 42 | 51.85% | 6 | 50.00% |
Ingo Molnar | 17 | 20.99% | 1 | 8.33% |
Al Viro | 15 | 18.52% | 1 | 8.33% |
Andrew Morton | 5 | 6.17% | 2 | 16.67% |
Christoph Lameter | 1 | 1.23% | 1 | 8.33% |
Eric W. Biedermann | 1 | 1.23% | 1 | 8.33% |
Total | 81 | 100.00% | 12 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 231 | 61.44% | 12 | 44.44% |
Nico Pitre | 48 | 12.77% | 2 | 7.41% |
Frédéric Weisbecker | 19 | 5.05% | 2 | 7.41% |
Eric Dumazet | 17 | 4.52% | 1 | 3.70% |
Peter Zijlstra | 17 | 4.52% | 1 | 3.70% |
Rik Van Riel | 17 | 4.52% | 2 | 7.41% |
Andrea Righi | 13 | 3.46% | 2 | 7.41% |
Laurent Vivier | 5 | 1.33% | 1 | 3.70% |
Paul E. McKenney | 4 | 1.06% | 2 | 7.41% |
Martin Schwidefsky | 3 | 0.80% | 1 | 3.70% |
Hidetoshi Seto | 2 | 0.53% | 1 | 3.70% |
Total | 376 | 100.00% | 27 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Eric W. Biedermann | 22 | 53.66% | 1 | 25.00% |
Mathieu Desnoyers | 14 | 34.15% | 1 | 25.00% |
Ingo Molnar | 4 | 9.76% | 1 | 25.00% |
Peter Zijlstra | 1 | 2.44% | 1 | 25.00% |
Total | 41 | 100.00% | 4 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Ingo Molnar | 58 | 39.19% | 6 | 26.09% |
Linus Torvalds | 28 | 18.92% | 2 | 8.70% |
Linus Torvalds (pre-git) | 24 | 16.22% | 7 | 30.43% |
Roland McGrath | 10 | 6.76% | 1 | 4.35% |
Paul E. McKenney | 7 | 4.73% | 1 | 4.35% |
Eric W. Biedermann | 6 | 4.05% | 1 | 4.35% |
Pavel Emelyanov | 5 | 3.38% | 1 | 4.35% |
David Howells | 3 | 2.03% | 1 | 4.35% |
Andrew Morton | 3 | 2.03% | 1 | 4.35% |
Oleg Nesterov | 3 | 2.03% | 1 | 4.35% |
Tejun Heo | 1 | 0.68% | 1 | 4.35% |
Total | 148 | 100.00% | 23 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 84 | 100.00% | 1 | 100.00% |
Total | 84 | 100.00% | 1 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Davidlohr Bueso A | 45 | 100.00% | 1 | 100.00% |
Total | 45 | 100.00% | 1 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 45 | 46.88% | 4 | 23.53% |
Oleg Nesterov | 12 | 12.50% | 1 | 5.88% |
Ingo Molnar | 10 | 10.42% | 4 | 23.53% |
Eric W. Biedermann | 8 | 8.33% | 1 | 5.88% |
Kirill Korotaev | 8 | 8.33% | 1 | 5.88% |
Cédric Le Goater | 4 | 4.17% | 1 | 5.88% |
Daniel Jacobowitz | 3 | 3.12% | 1 | 5.88% |
Andrew Morton | 3 | 3.12% | 2 | 11.76% |
Sukadev Bhattiprolu | 2 | 2.08% | 1 | 5.88% |
Serge E. Hallyn | 1 | 1.04% | 1 | 5.88% |
Total | 96 | 100.00% | 17 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Ingo Molnar | 20 | 54.05% | 1 | 16.67% |
Linus Torvalds (pre-git) | 9 | 24.32% | 2 | 33.33% |
Eric W. Biedermann | 6 | 16.22% | 2 | 33.33% |
Andrew Morton | 2 | 5.41% | 1 | 16.67% |
Total | 37 | 100.00% | 6 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 19 | 37.25% | 2 | 25.00% |
Oleg Nesterov | 11 | 21.57% | 1 | 12.50% |
Kirill Korotaev | 8 | 15.69% | 1 | 12.50% |
Ingo Molnar | 7 | 13.73% | 2 | 25.00% |
Eric W. Biedermann | 5 | 9.80% | 1 | 12.50% |
Andrew Morton | 1 | 1.96% | 1 | 12.50% |
Total | 51 | 100.00% | 8 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 101 | 99.02% | 1 | 50.00% |
Ionut Alexa | 1 | 0.98% | 1 | 50.00% |
Total | 102 | 100.00% | 2 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Balbir Singh | 170 | 74.24% | 2 | 28.57% |
Oleg Nesterov | 27 | 11.79% | 3 | 42.86% |
Kamezawa Hiroyuki | 25 | 10.92% | 1 | 14.29% |
Hugh Dickins | 7 | 3.06% | 1 | 14.29% |
Total | 229 | 100.00% | 7 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 65 | 29.82% | 6 | 16.67% |
Linus Torvalds (pre-git) | 49 | 22.48% | 13 | 36.11% |
Andrew Morton | 32 | 14.68% | 1 | 2.78% |
Ingo Molnar | 26 | 11.93% | 2 | 5.56% |
Davidlohr Bueso A | 10 | 4.59% | 2 | 5.56% |
Michal Hocko | 7 | 3.21% | 1 | 2.78% |
Linus Torvalds | 6 | 2.75% | 1 | 2.78% |
Konstantin Khlebnikov | 5 | 2.29% | 1 | 2.78% |
Balbir Singh | 5 | 2.29% | 1 | 2.78% |
Robert Love | 4 | 1.83% | 1 | 2.78% |
Eric Sesterhenn / Snakebyte | 3 | 1.38% | 1 | 2.78% |
Mandeep Singh Baines | 1 | 0.46% | 1 | 2.78% |
Vegard Nossum | 1 | 0.46% | 1 | 2.78% |
Tetsuo Handa | 1 | 0.46% | 1 | 2.78% |
Adrian Bunk | 1 | 0.46% | 1 | 2.78% |
David Rientjes | 1 | 0.46% | 1 | 2.78% |
Johannes Weiner | 1 | 0.46% | 1 | 2.78% |
Total | 218 | 100.00% | 36 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 43 | 100.00% | 1 | 100.00% |
Total | 43 | 100.00% | 1 | 100.00% |
static struct task_struct *find_child_reaper(struct task_struct *father)
__releases(&tasklist_lockContributors
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 11 | 78.57% | 2 | 66.67% |
Namhyung Kim | 3 | 21.43% | 1 | 33.33% |
Total | 14 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 74 | 60.66% | 7 | 87.50% |
Lennart Poettering | 48 | 39.34% | 1 | 12.50% |
Total | 122 | 100.00% | 8 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 95 | 97.94% | 7 | 87.50% |
Tejun Heo | 2 | 2.06% | 1 | 12.50% |
Total | 97 | 100.00% | 8 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 140 | 75.27% | 13 | 76.47% |
Daniel Jacobowitz | 27 | 14.52% | 1 | 5.88% |
Roland McGrath | 15 | 8.06% | 1 | 5.88% |
Matthias Kaehlcke | 2 | 1.08% | 1 | 5.88% |
Tejun Heo | 2 | 1.08% | 1 | 5.88% |
Total | 186 | 100.00% | 17 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Oleg Nesterov | 160 | 73.39% | 10 | 38.46% |
Ingo Molnar | 14 | 6.42% | 4 | 15.38% |
Roland McGrath | 11 | 5.05% | 3 | 11.54% |
Andrew Morton | 7 | 3.21% | 1 | 3.85% |
Linus Torvalds (pre-git) | 6 | 2.75% | 2 | 7.69% |
Linus Torvalds | 6 | 2.75% | 1 | 3.85% |
Daniel Jacobowitz | 5 | 2.29% | 2 | 7.69% |
Andrea Arcangeli | 4 | 1.83% | 1 | 3.85% |
Steve VanDeBogart | 3 | 1.38% | 1 | 3.85% |
Eric W. Biedermann | 2 | 0.92% | 1 | 3.85% |
Total | 218 | 100.00% | 26 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jeff Dike | 70 | 89.74% | 1 | 20.00% |
Tim Bird | 5 | 6.41% | 1 | 20.00% |
Anton Blanchard | 1 | 1.28% | 1 | 20.00% |
Ionut Alexa | 1 | 1.28% | 1 | 20.00% |
Eric Sandeen | 1 | 1.28% | 1 | 20.00% |
Total | 78 | 100.00% | 5 | 100.00% |
#else
static inline void check_stack_usage(void) {}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jeff Dike | 8 | 100.00% | 1 | 100.00% |
Total | 8 | 100.00% | 1 | 100.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().
*/