aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2009-09-23 18:56:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-24 10:20:59 -0400
commit0b7570e77f7c3abd43107dabc47ea89daf9a1cba (patch)
tree8dd93b4a189b4e98384d4470a289ecfb7818cc26 /kernel
parenta2322e1d272938d192d8c24cdacf57c0c7a2683f (diff)
do_wait() wakeup optimization: change __wake_up_parent() to use filtered wakeup
Ratan Nalumasu reported that in a process with many threads doing unnecessary wakeups. Every waiting thread in the process wakes up to loop through the children and see that the only ones it cares about are still not ready. Now that we have struct wait_opts we can change do_wait/__wake_up_parent to use filtered wakeups. We can make child_wait_callback() more clever later, right now it only checks eligible_child(). Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Roland McGrath <roland@redhat.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Ratan Nalumasu <rnalumasu@gmail.com> Cc: Vitaly Mayatskikh <vmayatsk@redhat.com> Acked-by: James Morris <jmorris@namei.org> Tested-by: Valdis Kletnieks <valdis.kletnieks@vt.edu> Acked-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index ef2dfa818bf1..7838b4d68774 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1097,6 +1097,7 @@ struct wait_opts {
1097 int __user *wo_stat; 1097 int __user *wo_stat;
1098 struct rusage __user *wo_rusage; 1098 struct rusage __user *wo_rusage;
1099 1099
1100 wait_queue_t child_wait;
1100 int notask_error; 1101 int notask_error;
1101}; 1102};
1102 1103
@@ -1570,20 +1571,35 @@ static int ptrace_do_wait(struct wait_opts *wo, struct task_struct *tsk)
1570 return 0; 1571 return 0;
1571} 1572}
1572 1573
1574static int child_wait_callback(wait_queue_t *wait, unsigned mode,
1575 int sync, void *key)
1576{
1577 struct wait_opts *wo = container_of(wait, struct wait_opts,
1578 child_wait);
1579 struct task_struct *p = key;
1580
1581 if (!eligible_child(wo, p))
1582 return 0;
1583
1584 return default_wake_function(wait, mode, sync, key);
1585}
1586
1573void __wake_up_parent(struct task_struct *p, struct task_struct *parent) 1587void __wake_up_parent(struct task_struct *p, struct task_struct *parent)
1574{ 1588{
1575 wake_up_interruptible_sync(&parent->signal->wait_chldexit); 1589 __wake_up_sync_key(&parent->signal->wait_chldexit,
1590 TASK_INTERRUPTIBLE, 1, p);
1576} 1591}
1577 1592
1578static long do_wait(struct wait_opts *wo) 1593static long do_wait(struct wait_opts *wo)
1579{ 1594{
1580 DECLARE_WAITQUEUE(wait, current);
1581 struct task_struct *tsk; 1595 struct task_struct *tsk;
1582 int retval; 1596 int retval;
1583 1597
1584 trace_sched_process_wait(wo->wo_pid); 1598 trace_sched_process_wait(wo->wo_pid);
1585 1599
1586 add_wait_queue(&current->signal->wait_chldexit,&wait); 1600 init_waitqueue_func_entry(&wo->child_wait, child_wait_callback);
1601 wo->child_wait.private = current;
1602 add_wait_queue(&current->signal->wait_chldexit, &wo->child_wait);
1587repeat: 1603repeat:
1588 /* 1604 /*
1589 * If there is nothing that can match our critiera just get out. 1605 * If there is nothing that can match our critiera just get out.
@@ -1624,7 +1640,8 @@ notask:
1624 } 1640 }
1625end: 1641end:
1626 __set_current_state(TASK_RUNNING); 1642 __set_current_state(TASK_RUNNING);
1627 remove_wait_queue(&current->signal->wait_chldexit,&wait); 1643 remove_wait_queue(&current->signal->wait_chldexit, &wo->child_wait);
1644
1628 if (wo->wo_info) { 1645 if (wo->wo_info) {
1629 struct siginfo __user *infop = wo->wo_info; 1646 struct siginfo __user *infop = wo->wo_info;
1630 1647