Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d3d891d authored by Dario Faggioli's avatar Dario Faggioli Committed by Ingo Molnar
Browse files

sched/deadline: Add SCHED_DEADLINE inheritance logic



Some method to deal with rt-mutexes and make sched_dl interact with
the current PI-coded is needed, raising all but trivial issues, that
needs (according to us) to be solved with some restructuring of
the pi-code (i.e., going toward a proxy execution-ish implementation).

This is under development, in the meanwhile, as a temporary solution,
what this commits does is:

 - ensure a pi-lock owner with waiters is never throttled down. Instead,
   when it runs out of runtime, it immediately gets replenished and it's
   deadline is postponed;

 - the scheduling parameters (relative deadline and default runtime)
   used for that replenishments --during the whole period it holds the
   pi-lock-- are the ones of the waiting task with earliest deadline.

Acting this way, we provide some kind of boosting to the lock-owner,
still by using the existing (actually, slightly modified by the previous
commit) pi-architecture.

We would stress the fact that this is only a surely needed, all but
clean solution to the problem. In the end it's only a way to re-start
discussion within the community. So, as always, comments, ideas, rants,
etc.. are welcome! :-)

Signed-off-by: default avatarDario Faggioli <raistlin@linux.it>
Signed-off-by: default avatarJuri Lelli <juri.lelli@gmail.com>
[ Added !RT_MUTEXES build fix. ]
Signed-off-by: default avatarPeter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-11-git-send-email-juri.lelli@gmail.com


Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent fb00aca4
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -1124,8 +1124,12 @@ struct sched_dl_entity {
	 * @dl_new tells if a new instance arrived. If so we must
	 * start executing it with full runtime and reset its absolute
	 * deadline;
	 *
	 * @dl_boosted tells if we are boosted due to DI. If so we are
	 * outside bandwidth enforcement mechanism (but only until we
	 * exit the critical section).
	 */
	int dl_throttled, dl_new;
	int dl_throttled, dl_new, dl_boosted;

	/*
	 * Bandwidth enforcement timer. Each -deadline task has its
@@ -1359,6 +1363,8 @@ struct task_struct {
	struct rb_node *pi_waiters_leftmost;
	/* Deadlock detection and priority inheritance handling */
	struct rt_mutex_waiter *pi_blocked_on;
	/* Top pi_waiters task */
	struct task_struct *pi_top_task;
#endif

#ifdef CONFIG_DEBUG_MUTEXES
+5 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ static inline int rt_task(struct task_struct *p)
#ifdef CONFIG_RT_MUTEXES
extern int rt_mutex_getprio(struct task_struct *p);
extern void rt_mutex_setprio(struct task_struct *p, int prio);
extern struct task_struct *rt_mutex_get_top_task(struct task_struct *task);
extern void rt_mutex_adjust_pi(struct task_struct *p);
static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
{
@@ -45,6 +46,10 @@ static inline int rt_mutex_getprio(struct task_struct *p)
{
	return p->normal_prio;
}
static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *task)
{
	return NULL;
}
# define rt_mutex_adjust_pi(p)		do { } while (0)
static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
{
+1 −0
Original line number Diff line number Diff line
@@ -1090,6 +1090,7 @@ static void rt_mutex_init_task(struct task_struct *p)
	p->pi_waiters = RB_ROOT;
	p->pi_waiters_leftmost = NULL;
	p->pi_blocked_on = NULL;
	p->pi_top_task = NULL;
#endif
}

+22 −9
Original line number Diff line number Diff line
@@ -96,13 +96,16 @@ static inline int
rt_mutex_waiter_less(struct rt_mutex_waiter *left,
		     struct rt_mutex_waiter *right)
{
	if (left->task->prio < right->task->prio)
	if (left->prio < right->prio)
		return 1;

	/*
	 * If both tasks are dl_task(), we check their deadlines.
	 * If both waiters have dl_prio(), we check the deadlines of the
	 * associated tasks.
	 * If left waiter has a dl_prio(), and we didn't return 1 above,
	 * then right waiter has a dl_prio() too.
	 */
	if (dl_prio(left->task->prio) && dl_prio(right->task->prio))
	if (dl_prio(left->prio))
		return (left->task->dl.deadline < right->task->dl.deadline);

	return 0;
@@ -197,10 +200,18 @@ int rt_mutex_getprio(struct task_struct *task)
	if (likely(!task_has_pi_waiters(task)))
		return task->normal_prio;

	return min(task_top_pi_waiter(task)->task->prio,
	return min(task_top_pi_waiter(task)->prio,
		   task->normal_prio);
}

struct task_struct *rt_mutex_get_top_task(struct task_struct *task)
{
	if (likely(!task_has_pi_waiters(task)))
		return NULL;

	return task_top_pi_waiter(task)->task;
}

/*
 * Adjust the priority of a task, after its pi_waiters got modified.
 *
@@ -210,7 +221,7 @@ static void __rt_mutex_adjust_prio(struct task_struct *task)
{
	int prio = rt_mutex_getprio(task);

	if (task->prio != prio)
	if (task->prio != prio || dl_prio(prio))
		rt_mutex_setprio(task, prio);
}

@@ -328,7 +339,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
	 * When deadlock detection is off then we check, if further
	 * priority adjustment is necessary.
	 */
	if (!detect_deadlock && waiter->task->prio == task->prio)
	if (!detect_deadlock && waiter->prio == task->prio)
		goto out_unlock_pi;

	lock = waiter->lock;
@@ -350,7 +361,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,

	/* Requeue the waiter */
	rt_mutex_dequeue(lock, waiter);
	waiter->task->prio = task->prio;
	waiter->prio = task->prio;
	rt_mutex_enqueue(lock, waiter);

	/* Release the task */
@@ -448,7 +459,7 @@ static int try_to_take_rt_mutex(struct rt_mutex *lock, struct task_struct *task,
	 * 3) it is top waiter
	 */
	if (rt_mutex_has_waiters(lock)) {
		if (task->prio >= rt_mutex_top_waiter(lock)->task->prio) {
		if (task->prio >= rt_mutex_top_waiter(lock)->prio) {
			if (!waiter || waiter != rt_mutex_top_waiter(lock))
				return 0;
		}
@@ -508,6 +519,7 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
	__rt_mutex_adjust_prio(task);
	waiter->task = task;
	waiter->lock = lock;
	waiter->prio = task->prio;

	/* Get the top priority waiter on the lock */
	if (rt_mutex_has_waiters(lock))
@@ -653,7 +665,8 @@ void rt_mutex_adjust_pi(struct task_struct *task)
	raw_spin_lock_irqsave(&task->pi_lock, flags);

	waiter = task->pi_blocked_on;
	if (!waiter || waiter->task->prio == task->prio) {
	if (!waiter || (waiter->prio == task->prio &&
			!dl_prio(task->prio))) {
		raw_spin_unlock_irqrestore(&task->pi_lock, flags);
		return;
	}
+1 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ struct rt_mutex_waiter {
	struct pid		*deadlock_task_pid;
	struct rt_mutex		*deadlock_lock;
#endif
	int prio;
};

/*
Loading