diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-11-27 11:32:46 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-09 04:03:05 -0500 |
commit | cd29fe6f2637cc2ccbda5ac65f5332d6bf5fa3c6 (patch) | |
tree | b4206012d424a8c0bce1f260d042c678db0602a2 /kernel/sched.c | |
parent | ab19cb23313733c55e0517607844b86720b35f5f (diff) |
sched: Sanitize fork() handling
Currently we try to do task placement in wake_up_new_task() after we do
the load-balance pass in sched_fork(). This yields complicated semantics
in that we have to deal with tasks on different RQs and the
set_task_cpu() calls in copy_process() and sched_fork()
Rename ->task_new() to ->task_fork() and call it from sched_fork()
before the balancing, this gives the policy a clear point to place the
task.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/sched.c')
-rw-r--r-- | kernel/sched.c | 47 |
1 files changed, 18 insertions, 29 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index c92670f8e097..33c903573132 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -1811,6 +1811,20 @@ static void cfs_rq_set_shares(struct cfs_rq *cfs_rq, unsigned long shares) | |||
1811 | 1811 | ||
1812 | static void calc_load_account_active(struct rq *this_rq); | 1812 | static void calc_load_account_active(struct rq *this_rq); |
1813 | 1813 | ||
1814 | static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) | ||
1815 | { | ||
1816 | set_task_rq(p, cpu); | ||
1817 | #ifdef CONFIG_SMP | ||
1818 | /* | ||
1819 | * After ->cpu is set up to a new value, task_rq_lock(p, ...) can be | ||
1820 | * successfuly executed on another CPU. We must ensure that updates of | ||
1821 | * per-task data have been completed by this moment. | ||
1822 | */ | ||
1823 | smp_wmb(); | ||
1824 | task_thread_info(p)->cpu = cpu; | ||
1825 | #endif | ||
1826 | } | ||
1827 | |||
1814 | #include "sched_stats.h" | 1828 | #include "sched_stats.h" |
1815 | #include "sched_idletask.c" | 1829 | #include "sched_idletask.c" |
1816 | #include "sched_fair.c" | 1830 | #include "sched_fair.c" |
@@ -1967,20 +1981,6 @@ inline int task_curr(const struct task_struct *p) | |||
1967 | return cpu_curr(task_cpu(p)) == p; | 1981 | return cpu_curr(task_cpu(p)) == p; |
1968 | } | 1982 | } |
1969 | 1983 | ||
1970 | static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) | ||
1971 | { | ||
1972 | set_task_rq(p, cpu); | ||
1973 | #ifdef CONFIG_SMP | ||
1974 | /* | ||
1975 | * After ->cpu is set up to a new value, task_rq_lock(p, ...) can be | ||
1976 | * successfuly executed on another CPU. We must ensure that updates of | ||
1977 | * per-task data have been completed by this moment. | ||
1978 | */ | ||
1979 | smp_wmb(); | ||
1980 | task_thread_info(p)->cpu = cpu; | ||
1981 | #endif | ||
1982 | } | ||
1983 | |||
1984 | static inline void check_class_changed(struct rq *rq, struct task_struct *p, | 1984 | static inline void check_class_changed(struct rq *rq, struct task_struct *p, |
1985 | const struct sched_class *prev_class, | 1985 | const struct sched_class *prev_class, |
1986 | int oldprio, int running) | 1986 | int oldprio, int running) |
@@ -2552,7 +2552,6 @@ static void __sched_fork(struct task_struct *p) | |||
2552 | void sched_fork(struct task_struct *p, int clone_flags) | 2552 | void sched_fork(struct task_struct *p, int clone_flags) |
2553 | { | 2553 | { |
2554 | int cpu = get_cpu(); | 2554 | int cpu = get_cpu(); |
2555 | unsigned long flags; | ||
2556 | 2555 | ||
2557 | __sched_fork(p); | 2556 | __sched_fork(p); |
2558 | 2557 | ||
@@ -2586,13 +2585,13 @@ void sched_fork(struct task_struct *p, int clone_flags) | |||
2586 | if (!rt_prio(p->prio)) | 2585 | if (!rt_prio(p->prio)) |
2587 | p->sched_class = &fair_sched_class; | 2586 | p->sched_class = &fair_sched_class; |
2588 | 2587 | ||
2588 | if (p->sched_class->task_fork) | ||
2589 | p->sched_class->task_fork(p); | ||
2590 | |||
2589 | #ifdef CONFIG_SMP | 2591 | #ifdef CONFIG_SMP |
2590 | cpu = select_task_rq(p, SD_BALANCE_FORK, 0); | 2592 | cpu = select_task_rq(p, SD_BALANCE_FORK, 0); |
2591 | #endif | 2593 | #endif |
2592 | local_irq_save(flags); | ||
2593 | update_rq_clock(cpu_rq(cpu)); | ||
2594 | set_task_cpu(p, cpu); | 2594 | set_task_cpu(p, cpu); |
2595 | local_irq_restore(flags); | ||
2596 | 2595 | ||
2597 | #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) | 2596 | #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) |
2598 | if (likely(sched_info_on())) | 2597 | if (likely(sched_info_on())) |
@@ -2625,17 +2624,7 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) | |||
2625 | rq = task_rq_lock(p, &flags); | 2624 | rq = task_rq_lock(p, &flags); |
2626 | BUG_ON(p->state != TASK_RUNNING); | 2625 | BUG_ON(p->state != TASK_RUNNING); |
2627 | update_rq_clock(rq); | 2626 | update_rq_clock(rq); |
2628 | 2627 | activate_task(rq, p, 0); | |
2629 | if (!p->sched_class->task_new || !current->se.on_rq) { | ||
2630 | activate_task(rq, p, 0); | ||
2631 | } else { | ||
2632 | /* | ||
2633 | * Let the scheduling class do new task startup | ||
2634 | * management (if any): | ||
2635 | */ | ||
2636 | p->sched_class->task_new(rq, p); | ||
2637 | inc_nr_running(rq); | ||
2638 | } | ||
2639 | trace_sched_wakeup_new(rq, p, 1); | 2628 | trace_sched_wakeup_new(rq, p, 1); |
2640 | check_preempt_curr(rq, p, WF_FORK); | 2629 | check_preempt_curr(rq, p, WF_FORK); |
2641 | #ifdef CONFIG_SMP | 2630 | #ifdef CONFIG_SMP |