aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-11-27 11:32:46 -0500
committerIngo Molnar <mingo@elte.hu>2009-12-09 04:03:05 -0500
commitcd29fe6f2637cc2ccbda5ac65f5332d6bf5fa3c6 (patch)
treeb4206012d424a8c0bce1f260d042c678db0602a2 /kernel
parentab19cb23313733c55e0517607844b86720b35f5f (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')
-rw-r--r--kernel/sched.c47
-rw-r--r--kernel/sched_fair.c28
2 files changed, 33 insertions, 42 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
1812static void calc_load_account_active(struct rq *this_rq); 1812static void calc_load_account_active(struct rq *this_rq);
1813 1813
1814static 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
1970static 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
1984static inline void check_class_changed(struct rq *rq, struct task_struct *p, 1984static 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)
2552void sched_fork(struct task_struct *p, int clone_flags) 2552void 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
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index 613c1c749677..44ec80ccfa85 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -1922,28 +1922,30 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
1922} 1922}
1923 1923
1924/* 1924/*
1925 * Share the fairness runtime between parent and child, thus the 1925 * called on fork with the child task as argument from the parent's context
1926 * total amount of pressure for CPU stays equal - new tasks 1926 * - child not yet on the tasklist
1927 * get a chance to run but frequent forkers are not allowed to 1927 * - preemption disabled
1928 * monopolize the CPU. Note: the parent runqueue is locked,
1929 * the child is not running yet.
1930 */ 1928 */
1931static void task_new_fair(struct rq *rq, struct task_struct *p) 1929static void task_fork_fair(struct task_struct *p)
1932{ 1930{
1933 struct cfs_rq *cfs_rq = task_cfs_rq(p); 1931 struct cfs_rq *cfs_rq = task_cfs_rq(current);
1934 struct sched_entity *se = &p->se, *curr = cfs_rq->curr; 1932 struct sched_entity *se = &p->se, *curr = cfs_rq->curr;
1935 int this_cpu = smp_processor_id(); 1933 int this_cpu = smp_processor_id();
1934 struct rq *rq = this_rq();
1935 unsigned long flags;
1936
1937 spin_lock_irqsave(&rq->lock, flags);
1936 1938
1937 sched_info_queued(p); 1939 if (unlikely(task_cpu(p) != this_cpu))
1940 __set_task_cpu(p, this_cpu);
1938 1941
1939 update_curr(cfs_rq); 1942 update_curr(cfs_rq);
1943
1940 if (curr) 1944 if (curr)
1941 se->vruntime = curr->vruntime; 1945 se->vruntime = curr->vruntime;
1942 place_entity(cfs_rq, se, 1); 1946 place_entity(cfs_rq, se, 1);
1943 1947
1944 /* 'curr' will be NULL if the child belongs to a different group */ 1948 if (sysctl_sched_child_runs_first && curr && entity_before(curr, se)) {
1945 if (sysctl_sched_child_runs_first && this_cpu == task_cpu(p) &&
1946 curr && entity_before(curr, se)) {
1947 /* 1949 /*
1948 * Upon rescheduling, sched_class::put_prev_task() will place 1950 * Upon rescheduling, sched_class::put_prev_task() will place
1949 * 'current' within the tree based on its new key value. 1951 * 'current' within the tree based on its new key value.
@@ -1952,7 +1954,7 @@ static void task_new_fair(struct rq *rq, struct task_struct *p)
1952 resched_task(rq->curr); 1954 resched_task(rq->curr);
1953 } 1955 }
1954 1956
1955 enqueue_task_fair(rq, p, 0); 1957 spin_unlock_irqrestore(&rq->lock, flags);
1956} 1958}
1957 1959
1958/* 1960/*
@@ -2052,7 +2054,7 @@ static const struct sched_class fair_sched_class = {
2052 2054
2053 .set_curr_task = set_curr_task_fair, 2055 .set_curr_task = set_curr_task_fair,
2054 .task_tick = task_tick_fair, 2056 .task_tick = task_tick_fair,
2055 .task_new = task_new_fair, 2057 .task_fork = task_fork_fair,
2056 2058
2057 .prio_changed = prio_changed_fair, 2059 .prio_changed = prio_changed_fair,
2058 .switched_to = switched_to_fair, 2060 .switched_to = switched_to_fair,