aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched_fair.c
diff options
context:
space:
mode:
authorRik van Riel <riel@redhat.com>2011-02-01 09:48:37 -0500
committerIngo Molnar <mingo@elte.hu>2011-02-03 08:20:32 -0500
commit2c13c919d9e9a3db9896143a501f83dcbbe1ced4 (patch)
tree4c326d2384ee0d09991cf5246baead5cfd08f3f9 /kernel/sched_fair.c
parent725e7580aaf98e9f7b22b8ccfc640ad0c09e2b08 (diff)
sched: Limit the scope of clear_buddies
The clear_buddies function does not seem to play well with the concept of hierarchical runqueues. In the following tree, task groups are represented by 'G', tasks by 'T', next by 'n' and last by 'l'. (nl) / \ G(nl) G / \ \ T(l) T(n) T This situation can arise when a task is woken up T(n), and the previously running task T(l) is marked last. When clear_buddies is called from either T(l) or T(n), the next and last buddies of the group G(nl) will be cleared. This is not the desired result, since we would like to be able to find the other type of buddy in many cases. This especially a worry when implementing yield_task_fair through the buddy system. The fix is simple: only clear the buddy type that the task itself is indicated to be. As an added bonus, we stop walking up the tree when the buddy has already been cleared or pointed elsewhere. Signed-off-by: Rik van Riel <riel@redhat.coM> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <20110201094837.6b0962a9@annuminas.surriel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/sched_fair.c')
-rw-r--r--kernel/sched_fair.c30
1 files changed, 23 insertions, 7 deletions
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index 4de9905228c4..a785e08202cf 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -995,19 +995,35 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
995 list_add_leaf_cfs_rq(cfs_rq); 995 list_add_leaf_cfs_rq(cfs_rq);
996} 996}
997 997
998static void __clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se) 998static void __clear_buddies_last(struct sched_entity *se)
999{ 999{
1000 if (!se || cfs_rq->last == se) 1000 for_each_sched_entity(se) {
1001 cfs_rq->last = NULL; 1001 struct cfs_rq *cfs_rq = cfs_rq_of(se);
1002 if (cfs_rq->last == se)
1003 cfs_rq->last = NULL;
1004 else
1005 break;
1006 }
1007}
1002 1008
1003 if (!se || cfs_rq->next == se) 1009static void __clear_buddies_next(struct sched_entity *se)
1004 cfs_rq->next = NULL; 1010{
1011 for_each_sched_entity(se) {
1012 struct cfs_rq *cfs_rq = cfs_rq_of(se);
1013 if (cfs_rq->next == se)
1014 cfs_rq->next = NULL;
1015 else
1016 break;
1017 }
1005} 1018}
1006 1019
1007static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se) 1020static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
1008{ 1021{
1009 for_each_sched_entity(se) 1022 if (cfs_rq->last == se)
1010 __clear_buddies(cfs_rq_of(se), se); 1023 __clear_buddies_last(se);
1024
1025 if (cfs_rq->next == se)
1026 __clear_buddies_next(se);
1011} 1027}
1012 1028
1013static void 1029static void