diff options
author | leochanj105 <43393724+leochanj105@users.noreply.github.com> | 2021-01-21 11:20:28 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-21 11:20:28 -0500 |
commit | e7425c838eded1f89c39550fae06cda63d8a0e16 (patch) | |
tree | f4b588502ea9a2ed70add08b2da5ea5c46048419 | |
parent | 3713d99f4b6a1fe6ec3bdf75ee67bf378ab325b0 (diff) |
GSN-EDF: Make sleep_next_period() a no-op if already completed due to budget exhaustion
Vanilla LITMUS-RT (without reservations) does not distinguish between
a period which voluntarily ends (via the complete_job() userspace call)
and a period which is forced to complete due to budget exhaustion.
This results in inconsistent behavior of the userspace API when budget
enforcement is enabled. Say a task's budget is set slightly below its actual
execution time. In this case, the task is suspended during its first job by
budget enforcement. When the second period starts, the task immediately
completes it's work and calls sleep_next_period(). From the perspective of
the task, it should enter its second job after calling sleep_next_period().
From the perspective of LITMUS-RT, the task is already in its second
period and will suspend the task until its _third_ period. This patch fixes
that bug for GSN-EDF by only suspending the task on
sleep_next_period() if the previous period was not force-completed by
budget enforcement.
-rw-r--r-- | litmus/sched_gsn_edf.c | 26 |
1 files changed, 24 insertions, 2 deletions
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index 76095cdb09a0..d4013aed6196 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -125,6 +125,9 @@ static struct bheap gsnedf_cpu_heap; | |||
125 | static rt_domain_t gsnedf; | 125 | static rt_domain_t gsnedf; |
126 | #define gsnedf_lock (gsnedf.ready_lock) | 126 | #define gsnedf_lock (gsnedf.ready_lock) |
127 | 127 | ||
128 | /* use the untouched rt_params->plugin_state as the forced completion bit */ | ||
129 | #define get_forced_completion(t) t->rt_param.plugin_state | ||
130 | #define set_forced_completion(t, forced) t->rt_param.plugin_state = forced | ||
128 | 131 | ||
129 | /* Uncomment this if you want to see all scheduling decisions in the | 132 | /* Uncomment this if you want to see all scheduling decisions in the |
130 | * TRACE() log. | 133 | * TRACE() log. |
@@ -474,8 +477,27 @@ static struct task_struct* gsnedf_schedule(struct task_struct * prev) | |||
474 | * this. Don't do a job completion if we block (can't have timers running | 477 | * this. Don't do a job completion if we block (can't have timers running |
475 | * for blocked jobs). | 478 | * for blocked jobs). |
476 | */ | 479 | */ |
477 | if (!np && (out_of_time || sleep)) | 480 | if (!np && (out_of_time || sleep)) { |
478 | curr_job_completion(!sleep); | 481 | if(sleep && get_forced_completion(entry->scheduled)) { |
482 | /* if we have a forced completion just before, simply | ||
483 | * set the completed flag to 0 | ||
484 | */ | ||
485 | TRACE_TASK(entry->scheduled, | ||
486 | "Task should complete normally, " | ||
487 | "but skipped due to a previous forced completion " | ||
488 | "caused by budget overrun\n"); | ||
489 | /* used current as in curr_job_completion */ | ||
490 | tsk_rt(current)->completed = 0; | ||
491 | } else { | ||
492 | /* if we have a forced completion now or a normal | ||
493 | * completion without previous forced completion, | ||
494 | * simply call curr_job_completion | ||
495 | */ | ||
496 | curr_job_completion(!sleep); | ||
497 | } | ||
498 | /* record whether there is a forced completion */ | ||
499 | set_forced_completion(entry->scheduled, out_of_time); | ||
500 | } | ||
479 | 501 | ||
480 | /* Link pending task if we became unlinked. | 502 | /* Link pending task if we became unlinked. |
481 | */ | 503 | */ |