Skip to content

Commit feff2e6

Browse files
Daniel Bristot de OliveiraPeter Zijlstra
authored andcommitted
sched/deadline: Unthrottle PI boosted threads while enqueuing
stress-ng has a test (stress-ng --cyclic) that creates a set of threads under SCHED_DEADLINE with the following parameters: dl_runtime = 10000 (10 us) dl_deadline = 100000 (100 us) dl_period = 100000 (100 us) These parameters are very aggressive. When using a system without HRTICK set, these threads can easily execute longer than the dl_runtime because the throttling happens with 1/HZ resolution. During the main part of the test, the system works just fine because the workload does not try to run over the 10 us. The problem happens at the end of the test, on the exit() path. During exit(), the threads need to do some cleanups that require real-time mutex locks, mainly those related to memory management, resulting in this scenario: Note: locks are rt_mutexes... ------------------------------------------------------------------------ TASK A: TASK B: TASK C: activation activation activation lock(a): OK! lock(b): OK! <overrun runtime> lock(a) -> block (task A owns it) -> self notice/set throttled +--< -> arm replenished timer | switch-out | lock(b) | -> <C prio > B prio> | -> boost TASK B | unlock(a) switch-out | -> handle lock a to B | -> wakeup(B) | -> B is throttled: | -> do not enqueue | switch-out | | +---------------------> replenishment timer -> TASK B is boosted: -> do not enqueue ------------------------------------------------------------------------ BOOM: TASK B is runnable but !enqueued, holding TASK C: the system crashes with hung task C. This problem is avoided by removing the throttle state from the boosted thread while boosting it (by TASK A in the example above), allowing it to be queued and run boosted. The next replenishment will take care of the runtime overrun, pushing the deadline further away. See the "while (dl_se->runtime <= 0)" on replenish_dl_entity() for more information. Reported-by: Mark Simmons <msimmons@redhat.com> Signed-off-by: Daniel Bristot de Oliveira <bristot@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Juri Lelli <juri.lelli@redhat.com> Tested-by: Mark Simmons <msimmons@redhat.com> Link: https://lkml.kernel.org/r/5076e003450835ec74e6fa5917d02c4fa41687e6.1600170294.git.bristot@redhat.com
1 parent 51cf18c commit feff2e6

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

kernel/sched/deadline.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,27 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)
15251525
*/
15261526
if (pi_task && dl_prio(pi_task->normal_prio) && p->dl.dl_boosted) {
15271527
pi_se = &pi_task->dl;
1528+
/*
1529+
* Because of delays in the detection of the overrun of a
1530+
* thread's runtime, it might be the case that a thread
1531+
* goes to sleep in a rt mutex with negative runtime. As
1532+
* a consequence, the thread will be throttled.
1533+
*
1534+
* While waiting for the mutex, this thread can also be
1535+
* boosted via PI, resulting in a thread that is throttled
1536+
* and boosted at the same time.
1537+
*
1538+
* In this case, the boost overrides the throttle.
1539+
*/
1540+
if (p->dl.dl_throttled) {
1541+
/*
1542+
* The replenish timer needs to be canceled. No
1543+
* problem if it fires concurrently: boosted threads
1544+
* are ignored in dl_task_timer().
1545+
*/
1546+
hrtimer_try_to_cancel(&p->dl.dl_timer);
1547+
p->dl.dl_throttled = 0;
1548+
}
15281549
} else if (!dl_prio(p->normal_prio)) {
15291550
/*
15301551
* Special case in which we have a !SCHED_DEADLINE task that is going

0 commit comments

Comments
 (0)