@@ -359,11 +359,15 @@ static inline void set_post_schedule(struct rq *rq)
rq->post_schedule = has_pushable_tasks(rq);
}
-static void enqueue_pushable_task(struct rq *rq, struct task_struct *p)
+static void
+enqueue_pushable_task(struct rq *rq, struct task_struct *p, bool head)
{
plist_del(&p->pushable_tasks, &rq->rt.pushable_tasks);
plist_node_init(&p->pushable_tasks, p->prio);
- plist_add(&p->pushable_tasks, &rq->rt.pushable_tasks);
+ if (head)
+ plist_add_head(&p->pushable_tasks, &rq->rt.pushable_tasks);
+ else
+ plist_add_tail(&p->pushable_tasks, &rq->rt.pushable_tasks);
/* Update the highest prio pushable task */
if (p->prio < rq->rt.highest_prio.next)
@@ -385,7 +389,8 @@ static void dequeue_pushable_task(struct rq *rq, struct task_struct *p)
#else
-static inline void enqueue_pushable_task(struct rq *rq, struct task_struct *p)
+static inline
+void enqueue_pushable_task(struct rq *rq, struct task_struct *p, bool head)
{
}
@@ -1260,7 +1265,7 @@ enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags)
enqueue_rt_entity(rt_se, flags & ENQUEUE_HEAD);
if (!task_current(rq, p) && p->nr_cpus_allowed > 1)
- enqueue_pushable_task(rq, p);
+ enqueue_pushable_task(rq, p, false);
}
static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags)
@@ -1507,7 +1512,16 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p)
* if it is still active
*/
if (on_rt_rq(&p->rt) && p->nr_cpus_allowed > 1)
- enqueue_pushable_task(rq, p);
+ /*
+ * put_prev_task_rt() is called by many functions,
+ * pick_next_task_rt() is the only one may have
+ * PREEMPT_ACTIVE set. So if detecting p(current
+ * task) is preempted in such case, we should
+ * enqueue it to the front of the pushable plist,
+ * as there may be multiple tasks with the same
+ * priority as p.
+ */
+ enqueue_pushable_task(rq, p, !!(preempt_count() & PREEMPT_ACTIVE));
}
#ifdef CONFIG_SMP
@@ -2091,7 +2105,7 @@ static void set_cpus_allowed_rt(struct task_struct *p,
rq->rt.rt_nr_migratory--;
} else {
if (!task_current(rq, p))
- enqueue_pushable_task(rq, p);
+ enqueue_pushable_task(rq, p, false);
rq->rt.rt_nr_migratory++;
}