diff options
| author | Dario Faggioli <raistlin@linux.it> | 2013-11-07 08:43:44 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2014-01-13 07:42:56 -0500 |
| commit | 2d3d891d3344159d5b452a645e355bbe29591e8b (patch) | |
| tree | ab7c4ef00b48d68efa2d57cabf8c3c86160f2406 | |
| parent | fb00aca474405f4fa8a8519c3179fed722eabd83 (diff) | |
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: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Added !RT_MUTEXES build fix. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-11-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
| -rw-r--r-- | include/linux/sched.h | 8 | ||||
| -rw-r--r-- | include/linux/sched/rt.h | 5 | ||||
| -rw-r--r-- | kernel/fork.c | 1 | ||||
| -rw-r--r-- | kernel/locking/rtmutex.c | 31 | ||||
| -rw-r--r-- | kernel/locking/rtmutex_common.h | 1 | ||||
| -rw-r--r-- | kernel/sched/core.c | 36 | ||||
| -rw-r--r-- | kernel/sched/deadline.c | 91 | ||||
| -rw-r--r-- | kernel/sched/sched.h | 14 | ||||
| -rw-r--r-- | kernel/trace/trace_sched_wakeup.c | 1 |
9 files changed, 134 insertions, 54 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index 9ea15019a5b6..13c53a99920f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -1124,8 +1124,12 @@ struct sched_dl_entity { | |||
| 1124 | * @dl_new tells if a new instance arrived. If so we must | 1124 | * @dl_new tells if a new instance arrived. If so we must |
| 1125 | * start executing it with full runtime and reset its absolute | 1125 | * start executing it with full runtime and reset its absolute |
| 1126 | * deadline; | 1126 | * deadline; |
| 1127 | * | ||
| 1128 | * @dl_boosted tells if we are boosted due to DI. If so we are | ||
| 1129 | * outside bandwidth enforcement mechanism (but only until we | ||
| 1130 | * exit the critical section). | ||
| 1127 | */ | 1131 | */ |
| 1128 | int dl_throttled, dl_new; | 1132 | int dl_throttled, dl_new, dl_boosted; |
| 1129 | 1133 | ||
| 1130 | /* | 1134 | /* |
| 1131 | * Bandwidth enforcement timer. Each -deadline task has its | 1135 | * Bandwidth enforcement timer. Each -deadline task has its |
| @@ -1359,6 +1363,8 @@ struct task_struct { | |||
| 1359 | struct rb_node *pi_waiters_leftmost; | 1363 | struct rb_node *pi_waiters_leftmost; |
| 1360 | /* Deadlock detection and priority inheritance handling */ | 1364 | /* Deadlock detection and priority inheritance handling */ |
| 1361 | struct rt_mutex_waiter *pi_blocked_on; | 1365 | struct rt_mutex_waiter *pi_blocked_on; |
| 1366 | /* Top pi_waiters task */ | ||
| 1367 | struct task_struct *pi_top_task; | ||
| 1362 | #endif | 1368 | #endif |
| 1363 | 1369 | ||
| 1364 | #ifdef CONFIG_DEBUG_MUTEXES | 1370 | #ifdef CONFIG_DEBUG_MUTEXES |
diff --git a/include/linux/sched/rt.h b/include/linux/sched/rt.h index 440434df3627..34e4ebea8fce 100644 --- a/include/linux/sched/rt.h +++ b/include/linux/sched/rt.h | |||
| @@ -35,6 +35,7 @@ static inline int rt_task(struct task_struct *p) | |||
| 35 | #ifdef CONFIG_RT_MUTEXES | 35 | #ifdef CONFIG_RT_MUTEXES |
| 36 | extern int rt_mutex_getprio(struct task_struct *p); | 36 | extern int rt_mutex_getprio(struct task_struct *p); |
| 37 | extern void rt_mutex_setprio(struct task_struct *p, int prio); | 37 | extern void rt_mutex_setprio(struct task_struct *p, int prio); |
| 38 | extern struct task_struct *rt_mutex_get_top_task(struct task_struct *task); | ||
| 38 | extern void rt_mutex_adjust_pi(struct task_struct *p); | 39 | extern void rt_mutex_adjust_pi(struct task_struct *p); |
| 39 | static inline bool tsk_is_pi_blocked(struct task_struct *tsk) | 40 | static inline bool tsk_is_pi_blocked(struct task_struct *tsk) |
| 40 | { | 41 | { |
| @@ -45,6 +46,10 @@ static inline int rt_mutex_getprio(struct task_struct *p) | |||
| 45 | { | 46 | { |
| 46 | return p->normal_prio; | 47 | return p->normal_prio; |
| 47 | } | 48 | } |
| 49 | static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *task) | ||
| 50 | { | ||
| 51 | return NULL; | ||
| 52 | } | ||
| 48 | # define rt_mutex_adjust_pi(p) do { } while (0) | 53 | # define rt_mutex_adjust_pi(p) do { } while (0) |
| 49 | static inline bool tsk_is_pi_blocked(struct task_struct *tsk) | 54 | static inline bool tsk_is_pi_blocked(struct task_struct *tsk) |
| 50 | { | 55 | { |
diff --git a/kernel/fork.c b/kernel/fork.c index 7049ae526a54..01b450a61abd 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -1090,6 +1090,7 @@ static void rt_mutex_init_task(struct task_struct *p) | |||
| 1090 | p->pi_waiters = RB_ROOT; | 1090 | p->pi_waiters = RB_ROOT; |
| 1091 | p->pi_waiters_leftmost = NULL; | 1091 | p->pi_waiters_leftmost = NULL; |
| 1092 | p->pi_blocked_on = NULL; | 1092 | p->pi_blocked_on = NULL; |
| 1093 | p->pi_top_task = NULL; | ||
| 1093 | #endif | 1094 | #endif |
| 1094 | } | 1095 | } |
| 1095 | 1096 | ||
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index 3bf0aa68dd3f..2e960a2bab81 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c | |||
| @@ -96,13 +96,16 @@ static inline int | |||
| 96 | rt_mutex_waiter_less(struct rt_mutex_waiter *left, | 96 | rt_mutex_waiter_less(struct rt_mutex_waiter *left, |
| 97 | struct rt_mutex_waiter *right) | 97 | struct rt_mutex_waiter *right) |
| 98 | { | 98 | { |
| 99 | if (left->task->prio < right->task->prio) | 99 | if (left->prio < right->prio) |
| 100 | return 1; | 100 | return 1; |
| 101 | 101 | ||
| 102 | /* | 102 | /* |
| 103 | * If both tasks are dl_task(), we check their deadlines. | 103 | * If both waiters have dl_prio(), we check the deadlines of the |
| 104 | * associated tasks. | ||
| 105 | * If left waiter has a dl_prio(), and we didn't return 1 above, | ||
| 106 | * then right waiter has a dl_prio() too. | ||
| 104 | */ | 107 | */ |
| 105 | if (dl_prio(left->task->prio) && dl_prio(right->task->prio)) | 108 | if (dl_prio(left->prio)) |
| 106 | return (left->task->dl.deadline < right->task->dl.deadline); | 109 | return (left->task->dl.deadline < right->task->dl.deadline); |
| 107 | 110 | ||
| 108 | return 0; | 111 | return 0; |
| @@ -197,10 +200,18 @@ int rt_mutex_getprio(struct task_struct *task) | |||
| 197 | if (likely(!task_has_pi_waiters(task))) | 200 | if (likely(!task_has_pi_waiters(task))) |
| 198 | return task->normal_prio; | 201 | return task->normal_prio; |
| 199 | 202 | ||
| 200 | return min(task_top_pi_waiter(task)->task->prio, | 203 | return min(task_top_pi_waiter(task)->prio, |
| 201 | task->normal_prio); | 204 | task->normal_prio); |
| 202 | } | 205 | } |
| 203 | 206 | ||
| 207 | struct task_struct *rt_mutex_get_top_task(struct task_struct *task) | ||
| 208 | { | ||
| 209 | if (likely(!task_has_pi_waiters(task))) | ||
| 210 | return NULL; | ||
| 211 | |||
| 212 | return task_top_pi_waiter(task)->task; | ||
| 213 | } | ||
| 214 | |||
| 204 | /* | 215 | /* |
| 205 | * Adjust the priority of a task, after its pi_waiters got modified. | 216 | * Adjust the priority of a task, after its pi_waiters got modified. |
| 206 | * | 217 | * |
| @@ -210,7 +221,7 @@ static void __rt_mutex_adjust_prio(struct task_struct *task) | |||
| 210 | { | 221 | { |
| 211 | int prio = rt_mutex_getprio(task); | 222 | int prio = rt_mutex_getprio(task); |
| 212 | 223 | ||
| 213 | if (task->prio != prio) | 224 | if (task->prio != prio || dl_prio(prio)) |
| 214 | rt_mutex_setprio(task, prio); | 225 | rt_mutex_setprio(task, prio); |
| 215 | } | 226 | } |
| 216 | 227 | ||
| @@ -328,7 +339,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, | |||
| 328 | * When deadlock detection is off then we check, if further | 339 | * When deadlock detection is off then we check, if further |
| 329 | * priority adjustment is necessary. | 340 | * priority adjustment is necessary. |
| 330 | */ | 341 | */ |
| 331 | if (!detect_deadlock && waiter->task->prio == task->prio) | 342 | if (!detect_deadlock && waiter->prio == task->prio) |
| 332 | goto out_unlock_pi; | 343 | goto out_unlock_pi; |
| 333 | 344 | ||
| 334 | lock = waiter->lock; | 345 | lock = waiter->lock; |
| @@ -350,7 +361,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, | |||
| 350 | 361 | ||
| 351 | /* Requeue the waiter */ | 362 | /* Requeue the waiter */ |
| 352 | rt_mutex_dequeue(lock, waiter); | 363 | rt_mutex_dequeue(lock, waiter); |
| 353 | waiter->task->prio = task->prio; | 364 | waiter->prio = task->prio; |
| 354 | rt_mutex_enqueue(lock, waiter); | 365 | rt_mutex_enqueue(lock, waiter); |
| 355 | 366 | ||
| 356 | /* Release the task */ | 367 | /* Release the task */ |
| @@ -448,7 +459,7 @@ static int try_to_take_rt_mutex(struct rt_mutex *lock, struct task_struct *task, | |||
| 448 | * 3) it is top waiter | 459 | * 3) it is top waiter |
| 449 | */ | 460 | */ |
| 450 | if (rt_mutex_has_waiters(lock)) { | 461 | if (rt_mutex_has_waiters(lock)) { |
| 451 | if (task->prio >= rt_mutex_top_waiter(lock)->task->prio) { | 462 | if (task->prio >= rt_mutex_top_waiter(lock)->prio) { |
| 452 | if (!waiter || waiter != rt_mutex_top_waiter(lock)) | 463 | if (!waiter || waiter != rt_mutex_top_waiter(lock)) |
| 453 | return 0; | 464 | return 0; |
| 454 | } | 465 | } |
| @@ -508,6 +519,7 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, | |||
| 508 | __rt_mutex_adjust_prio(task); | 519 | __rt_mutex_adjust_prio(task); |
| 509 | waiter->task = task; | 520 | waiter->task = task; |
| 510 | waiter->lock = lock; | 521 | waiter->lock = lock; |
| 522 | waiter->prio = task->prio; | ||
| 511 | 523 | ||
| 512 | /* Get the top priority waiter on the lock */ | 524 | /* Get the top priority waiter on the lock */ |
| 513 | if (rt_mutex_has_waiters(lock)) | 525 | if (rt_mutex_has_waiters(lock)) |
| @@ -653,7 +665,8 @@ void rt_mutex_adjust_pi(struct task_struct *task) | |||
| 653 | raw_spin_lock_irqsave(&task->pi_lock, flags); | 665 | raw_spin_lock_irqsave(&task->pi_lock, flags); |
| 654 | 666 | ||
| 655 | waiter = task->pi_blocked_on; | 667 | waiter = task->pi_blocked_on; |
| 656 | if (!waiter || waiter->task->p | ||
