aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched_fair.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sched_fair.c')
-rw-r--r--kernel/sched_fair.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index ebd6de8d17fd..a6b1db8a0bd8 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -341,9 +341,6 @@ static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
341 cfs_rq->rb_leftmost = next_node; 341 cfs_rq->rb_leftmost = next_node;
342 } 342 }
343 343
344 if (cfs_rq->next == se)
345 cfs_rq->next = NULL;
346
347 rb_erase(&se->run_node, &cfs_rq->tasks_timeline); 344 rb_erase(&se->run_node, &cfs_rq->tasks_timeline);
348} 345}
349 346
@@ -741,6 +738,12 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int sleep)
741#endif 738#endif
742 } 739 }
743 740
741 if (cfs_rq->last == se)
742 cfs_rq->last = NULL;
743
744 if (cfs_rq->next == se)
745 cfs_rq->next = NULL;
746
744 if (se != cfs_rq->curr) 747 if (se != cfs_rq->curr)
745 __dequeue_entity(cfs_rq, se); 748 __dequeue_entity(cfs_rq, se);
746 account_entity_dequeue(cfs_rq, se); 749 account_entity_dequeue(cfs_rq, se);
@@ -798,10 +801,13 @@ static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
798{ 801{
799 struct sched_entity *se = __pick_next_entity(cfs_rq); 802 struct sched_entity *se = __pick_next_entity(cfs_rq);
800 803
801 if (!cfs_rq->next || wakeup_preempt_entity(cfs_rq->next, se) == 1) 804 if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, se) < 1)
802 return se; 805 return cfs_rq->next;
803 806
804 return cfs_rq->next; 807 if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, se) < 1)
808 return cfs_rq->last;
809
810 return se;
805} 811}
806 812
807static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev) 813static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
@@ -1319,10 +1325,11 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)
1319static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync) 1325static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync)
1320{ 1326{
1321 struct task_struct *curr = rq->curr; 1327 struct task_struct *curr = rq->curr;
1322 struct cfs_rq *cfs_rq = task_cfs_rq(curr);
1323 struct sched_entity *se = &curr->se, *pse = &p->se; 1328 struct sched_entity *se = &curr->se, *pse = &p->se;
1324 1329
1325 if (unlikely(rt_prio(p->prio))) { 1330 if (unlikely(rt_prio(p->prio))) {
1331 struct cfs_rq *cfs_rq = task_cfs_rq(curr);
1332
1326 update_rq_clock(rq); 1333 update_rq_clock(rq);
1327 update_curr(cfs_rq); 1334 update_curr(cfs_rq);
1328 resched_task(curr); 1335 resched_task(curr);
@@ -1335,6 +1342,17 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync)
1335 if (unlikely(se == pse)) 1342 if (unlikely(se == pse))
1336 return; 1343 return;
1337 1344
1345 /*
1346 * Only set the backward buddy when the current task is still on the
1347 * rq. This can happen when a wakeup gets interleaved with schedule on
1348 * the ->pre_schedule() or idle_balance() point, either of which can
1349 * drop the rq lock.
1350 *
1351 * Also, during early boot the idle thread is in the fair class, for
1352 * obvious reasons its a bad idea to schedule back to the idle thread.
1353 */
1354 if (sched_feat(LAST_BUDDY) && likely(se->on_rq && curr != rq->idle))
1355 cfs_rq_of(se)->last = se;
1338 cfs_rq_of(pse)->next = pse; 1356 cfs_rq_of(pse)->next = pse;
1339 1357
1340 /* 1358 /*