sched/rtmutex: Refactor rt_mutex_setprio()
With the introduction of SCHED_DEADLINE the whole notion that priority is a single number is gone, therefore the @prio argument to rt_mutex_setprio() doesn't make sense anymore. So rework the code to pass a pi_task instead. Note this also fixes a problem with pi_top_task caching; previously we would not set the pointer (call rt_mutex_update_top_task) if the priority didn't change, this could lead to a stale pointer. As for the XXX, I think its fine to use pi_task->prio, because if it differs from waiter->prio, a PI chain update is immenent. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: juri.lelli@arm.com Cc: bigeasy@linutronix.de Cc: xlpang@redhat.com Cc: rostedt@goodmis.org Cc: mathieu.desnoyers@efficios.com Cc: jdesfossez@efficios.com Cc: bristot@redhat.com Link: http://lkml.kernel.org/r/20170323150216.303827095@infradead.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:

committed by
Thomas Gleixner

parent
aa2bfe5536
commit
acd58620e4
@@ -3671,10 +3671,25 @@ EXPORT_SYMBOL(default_wake_function);
|
||||
|
||||
#ifdef CONFIG_RT_MUTEXES
|
||||
|
||||
static inline int __rt_effective_prio(struct task_struct *pi_task, int prio)
|
||||
{
|
||||
if (pi_task)
|
||||
prio = min(prio, pi_task->prio);
|
||||
|
||||
return prio;
|
||||
}
|
||||
|
||||
static inline int rt_effective_prio(struct task_struct *p, int prio)
|
||||
{
|
||||
struct task_struct *pi_task = rt_mutex_get_top_task(p);
|
||||
|
||||
return __rt_effective_prio(pi_task, prio);
|
||||
}
|
||||
|
||||
/*
|
||||
* rt_mutex_setprio - set the current priority of a task
|
||||
* @p: task
|
||||
* @prio: prio value (kernel-internal form)
|
||||
* @p: task to boost
|
||||
* @pi_task: donor task
|
||||
*
|
||||
* This function changes the 'effective' priority of a task. It does
|
||||
* not touch ->normal_prio like __setscheduler().
|
||||
@@ -3682,18 +3697,42 @@ EXPORT_SYMBOL(default_wake_function);
|
||||
* Used by the rt_mutex code to implement priority inheritance
|
||||
* logic. Call site only calls if the priority of the task changed.
|
||||
*/
|
||||
void rt_mutex_setprio(struct task_struct *p, int prio)
|
||||
void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task)
|
||||
{
|
||||
int oldprio, queued, running, queue_flag =
|
||||
int prio, oldprio, queued, running, queue_flag =
|
||||
DEQUEUE_SAVE | DEQUEUE_MOVE | DEQUEUE_NOCLOCK;
|
||||
const struct sched_class *prev_class;
|
||||
struct rq_flags rf;
|
||||
struct rq *rq;
|
||||
|
||||
BUG_ON(prio > MAX_PRIO);
|
||||
/* XXX used to be waiter->prio, not waiter->task->prio */
|
||||
prio = __rt_effective_prio(pi_task, p->normal_prio);
|
||||
|
||||
/*
|
||||
* If nothing changed; bail early.
|
||||
*/
|
||||
if (p->pi_top_task == pi_task && prio == p->prio && !dl_prio(prio))
|
||||
return;
|
||||
|
||||
rq = __task_rq_lock(p, &rf);
|
||||
update_rq_clock(rq);
|
||||
/*
|
||||
* Set under pi_lock && rq->lock, such that the value can be used under
|
||||
* either lock.
|
||||
*
|
||||
* Note that there is loads of tricky to make this pointer cache work
|
||||
* right. rt_mutex_slowunlock()+rt_mutex_postunlock() work together to
|
||||
* ensure a task is de-boosted (pi_task is set to NULL) before the
|
||||
* task is allowed to run again (and can exit). This ensures the pointer
|
||||
* points to a blocked task -- which guaratees the task is present.
|
||||
*/
|
||||
p->pi_top_task = pi_task;
|
||||
|
||||
/*
|
||||
* For FIFO/RR we only need to set prio, if that matches we're done.
|
||||
*/
|
||||
if (prio == p->prio && !dl_prio(prio))
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
* Idle task boosting is a nono in general. There is one
|
||||
@@ -3713,9 +3752,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
rt_mutex_update_top_task(p);
|
||||
|
||||
trace_sched_pi_setprio(p, prio);
|
||||
trace_sched_pi_setprio(p, prio); /* broken */
|
||||
oldprio = p->prio;
|
||||
|
||||
if (oldprio == prio)
|
||||
@@ -3739,7 +3776,6 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
|
||||
* running task
|
||||
*/
|
||||
if (dl_prio(prio)) {
|
||||
struct task_struct *pi_task = rt_mutex_get_top_task(p);
|
||||
if (!dl_prio(p->normal_prio) ||
|
||||
(pi_task && dl_entity_preempt(&pi_task->dl, &p->dl))) {
|
||||
p->dl.dl_boosted = 1;
|
||||
@@ -3777,6 +3813,11 @@ out_unlock:
|
||||
balance_callback(rq);
|
||||
preempt_enable();
|
||||
}
|
||||
#else
|
||||
static inline int rt_effective_prio(struct task_struct *p, int prio)
|
||||
{
|
||||
return prio;
|
||||
}
|
||||
#endif
|
||||
|
||||
void set_user_nice(struct task_struct *p, long nice)
|
||||
@@ -4023,10 +4064,9 @@ static void __setscheduler(struct rq *rq, struct task_struct *p,
|
||||
* Keep a potential priority boosting if called from
|
||||
* sched_setscheduler().
|
||||
*/
|
||||
p->prio = normal_prio(p);
|
||||
if (keep_boost)
|
||||
p->prio = rt_mutex_get_effective_prio(p, normal_prio(p));
|
||||
else
|
||||
p->prio = normal_prio(p);
|
||||
p->prio = rt_effective_prio(p, p->prio);
|
||||
|
||||
if (dl_prio(p->prio))
|
||||
p->sched_class = &dl_sched_class;
|
||||
@@ -4313,7 +4353,7 @@ change:
|
||||
* the runqueue. This will be done when the task deboost
|
||||
* itself.
|
||||
*/
|
||||
new_effective_prio = rt_mutex_get_effective_prio(p, newprio);
|
||||
new_effective_prio = rt_effective_prio(p, newprio);
|
||||
if (new_effective_prio == oldprio)
|
||||
queue_flags &= ~DEQUEUE_MOVE;
|
||||
}
|
||||
|
Reference in New Issue
Block a user