do_wait() optimization: do not place sub-threads on task_struct->children list

Thanks to Roland who pointed out de_thread() issues.

Currently we add sub-threads to ->real_parent->children list.  This buys
nothing but slows down do_wait().

With this patch ->children contains only main threads (group leaders).
The only complication is that forget_original_parent() should iterate over
sub-threads by hand, and de_thread() needs another list_replace() when it
changes ->group_leader.

Henceforth do_wait_thread() can never see task_detached() && !EXIT_DEAD
tasks, we can remove this check (and we can unify do_wait_thread() and
ptrace_do_wait()).

This change can confuse the optimistic search in mm_update_next_owner(),
but this is fixable and minor.

Perhaps badness() and oom_kill_process() should be updated, but they
should be fixed in any case.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Ratan Nalumasu <rnalumasu@gmail.com>
Cc: Vitaly Mayatskikh <vmayatsk@redhat.com>
Cc: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Oleg Nesterov 2009-12-17 15:27:15 -08:00 committed by Linus Torvalds
parent 0f67b0b039
commit 9cd80bbb07
3 changed files with 20 additions and 20 deletions

View file

@ -826,7 +826,9 @@ static int de_thread(struct task_struct *tsk)
attach_pid(tsk, PIDTYPE_PID, task_pid(leader)); attach_pid(tsk, PIDTYPE_PID, task_pid(leader));
transfer_pid(leader, tsk, PIDTYPE_PGID); transfer_pid(leader, tsk, PIDTYPE_PGID);
transfer_pid(leader, tsk, PIDTYPE_SID); transfer_pid(leader, tsk, PIDTYPE_SID);
list_replace_rcu(&leader->tasks, &tsk->tasks); list_replace_rcu(&leader->tasks, &tsk->tasks);
list_replace_init(&leader->sibling, &tsk->sibling);
tsk->group_leader = tsk; tsk->group_leader = tsk;
leader->group_leader = tsk; leader->group_leader = tsk;

View file

@ -68,10 +68,10 @@ static void __unhash_process(struct task_struct *p)
detach_pid(p, PIDTYPE_SID); detach_pid(p, PIDTYPE_SID);
list_del_rcu(&p->tasks); list_del_rcu(&p->tasks);
list_del_init(&p->sibling);
__get_cpu_var(process_counts)--; __get_cpu_var(process_counts)--;
} }
list_del_rcu(&p->thread_group); list_del_rcu(&p->thread_group);
list_del_init(&p->sibling);
} }
/* /*
@ -736,12 +736,9 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
/* /*
* Any that need to be release_task'd are put on the @dead list. * Any that need to be release_task'd are put on the @dead list.
*/ */
static void reparent_thread(struct task_struct *father, struct task_struct *p, static void reparent_leader(struct task_struct *father, struct task_struct *p,
struct list_head *dead) struct list_head *dead)
{ {
if (p->pdeath_signal)
group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p);
list_move_tail(&p->sibling, &p->real_parent->children); list_move_tail(&p->sibling, &p->real_parent->children);
if (task_detached(p)) if (task_detached(p))
@ -780,12 +777,18 @@ static void forget_original_parent(struct task_struct *father)
reaper = find_new_reaper(father); reaper = find_new_reaper(father);
list_for_each_entry_safe(p, n, &father->children, sibling) { list_for_each_entry_safe(p, n, &father->children, sibling) {
p->real_parent = reaper; struct task_struct *t = p;
if (p->parent == father) { do {
BUG_ON(task_ptrace(p)); t->real_parent = reaper;
p->parent = p->real_parent; if (t->parent == father) {
} BUG_ON(task_ptrace(t));
reparent_thread(father, p, &dead_children); 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);
} }
write_unlock_irq(&tasklist_lock); write_unlock_irq(&tasklist_lock);
@ -1551,14 +1554,9 @@ static int do_wait_thread(struct wait_opts *wo, struct task_struct *tsk)
struct task_struct *p; struct task_struct *p;
list_for_each_entry(p, &tsk->children, sibling) { list_for_each_entry(p, &tsk->children, sibling) {
/* int ret = wait_consider_task(wo, 0, p);
* Do not consider detached threads. if (ret)
*/ return ret;
if (!task_detached(p)) {
int ret = wait_consider_task(wo, 0, p);
if (ret)
return ret;
}
} }
return 0; return 0;

View file

@ -1291,7 +1291,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
} }
if (likely(p->pid)) { if (likely(p->pid)) {
list_add_tail(&p->sibling, &p->real_parent->children);
tracehook_finish_clone(p, clone_flags, trace); tracehook_finish_clone(p, clone_flags, trace);
if (thread_group_leader(p)) { if (thread_group_leader(p)) {
@ -1303,6 +1302,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->signal->tty = tty_kref_get(current->signal->tty); p->signal->tty = tty_kref_get(current->signal->tty);
attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
attach_pid(p, PIDTYPE_SID, task_session(current)); attach_pid(p, PIDTYPE_SID, task_session(current));
list_add_tail(&p->sibling, &p->real_parent->children);
list_add_tail_rcu(&p->tasks, &init_task.tasks); list_add_tail_rcu(&p->tasks, &init_task.tasks);
__get_cpu_var(process_counts)++; __get_cpu_var(process_counts)++;
} }