aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Bakita <jbakita@cs.unc.edu>2020-03-07 20:20:17 -0500
committerJoshua Bakita <jbakita@cs.unc.edu>2020-03-07 20:20:17 -0500
commitfbcf3074b978275274270dcbaaf40da62b6f0b69 (patch)
treeb1bd19115eacaf64b75e553bd1fecca1735672c2
parentf523a230da7c2813b03f2e9e1d9d2e8848987052 (diff)
Remove dead code, handle delayed migrations, and fix invalid memory handle
As we should never see one of our job completion functions called on a task after it goes through edfsc_task_exit(), simplify that logic to just handle migrations. Also, hold a reference to the task_struct so that it still exists when task_deadline_callback() is called.
-rw-r--r--include/litmus/rt_param.h1
-rw-r--r--litmus/sched_edfsc.c83
2 files changed, 50 insertions, 34 deletions
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h
index b9169fb37d46..22ce3da19245 100644
--- a/include/litmus/rt_param.h
+++ b/include/litmus/rt_param.h
@@ -122,7 +122,6 @@ struct edfsc_params {
122 cont_domain_t *domain; 122 cont_domain_t *domain;
123 struct task_struct *container_task; 123 struct task_struct *container_task;
124 int id; 124 int id;
125 int will_remove;
126 int can_release; //only used for containers 125 int can_release; //only used for containers
127 // Moved these to the struct task_struct in include/linux/sched.h so that 126 // Moved these to the struct task_struct in include/linux/sched.h so that
128 // the runtime can build 127 // the runtime can build
diff --git a/litmus/sched_edfsc.c b/litmus/sched_edfsc.c
index 5711a09a6c36..c66461bcfca7 100644
--- a/litmus/sched_edfsc.c
+++ b/litmus/sched_edfsc.c
@@ -439,16 +439,25 @@ static void c_remove_task(struct task_struct *t)
439 future_sys_util -= get_rt_utilization(t); 439 future_sys_util -= get_rt_utilization(t);
440} 440}
441 441
442static void remove_task(struct task_struct *t) 442/**
443 * Remove a task from it's current domain and put it in a different domain.
444 * Must be called at the greater time of job completion and deadline to respect
445 * EDF-sc invariants.
446 */
447static void migrate_task(struct task_struct *t)
443{ 448{
444 BUG_ON(!t); 449 BUG_ON(!t);
445 BUG_ON(is_container(t)); 450 BUG_ON(is_container(t));
451 BUG_ON(!tsk_rt(t)->edfsc_params.move_to);
446 452
453 if (is_queued(t))
454 remove(tsk_rt(t)->domain, t);
447 if (is_fixed(t)) { 455 if (is_fixed(t)) {
448 c_remove_task(t); 456 c_remove_task(t);
449 } else { 457 } else {
450 g_remove_task(t); 458 g_remove_task(t);
451 } 459 }
460 tsk_rt(t)->edfsc_params.move_to = NULL;
452} 461}
453 462
454// migrating or container task job_completion, called from edfsc_gschedule 463// migrating or container task job_completion, called from edfsc_gschedule
@@ -463,17 +472,14 @@ static noinline void g_job_completion(struct task_struct* t, int forced)
463 tsk_rt(t)->completed = 0; 472 tsk_rt(t)->completed = 0;
464 unlink(t); 473 unlink(t);
465 474
466 // When migrating is being removed, or turned into a fixed task 475 // When a migrating task is being turned turned into a fixed task
467 if (is_migrating(t) && tsk_rt(t)->edfsc_params.will_remove) { 476 if (is_migrating(t) && tsk_rt(t)->edfsc_params.move_to) {
468 if (t->rt_param.job_params.lateness > 0) { 477 if (t->rt_param.job_params.lateness > 0) {
469 // remove the task now 478 // Don't wait if late
470 if (is_queued(t)) 479 migrate_task(t);
471 remove(tsk_rt(t)->domain, t); 480 } else {
472 //g_remove_task will properly add t to the move_to container 481 hrtimer_start(&t->edfsc_deadline_timer, ns_to_ktime(get_deadline(t)),
473 g_remove_task(t); 482 HRTIMER_MODE_ABS_PINNED);
474 }
475 else {
476 //TODO: deadline timer to call g_remove_task
477 } 483 }
478 // When a migrating job finishes 484 // When a migrating job finishes
479 } else if (is_migrating(t)) { 485 } else if (is_migrating(t)) {
@@ -528,18 +534,8 @@ static void c_job_completion(struct task_struct* t, int forced)
528 TRACE_TASK(t, "job_completion(forced=%d).\n", forced); 534 TRACE_TASK(t, "job_completion(forced=%d).\n", forced);
529 535
530 tsk_rt(t)->completed = 0; 536 tsk_rt(t)->completed = 0;
531 537 prepare_for_next_period(t);
532 if (tsk_rt(t)->edfsc_params.will_remove) { 538 requeue(t);
533 if (t->rt_param.job_params.lateness > 0) {
534 // remove the task now
535 if (is_queued(t))
536 remove(tsk_rt(t)->domain, t);
537 c_remove_task(t);
538 }
539 } else {
540 prepare_for_next_period(t);
541 requeue(t);
542 }
543} 539}
544 540
545// need to update cpu entries after global scheduling 541// need to update cpu entries after global scheduling
@@ -947,9 +943,8 @@ static enum hrtimer_restart container_boundary(struct hrtimer *timer)
947 // is actually working 943 // is actually working
948 list_for_each(it, &migrating_tasks) { 944 list_for_each(it, &migrating_tasks) {
949 struct task_struct* t = task_of_list_node(it); 945 struct task_struct* t = task_of_list_node(it);
950 if (!(tsk_rt(t)->edfsc_params.will_remove) && !is_released(t, now) 946 if (!(tsk_rt(t)->edfsc_params.move_to) && !is_released(t, now)
951 && get_deadline(t) < get_deadline(&container_tasks[0]) + get_rt_period(&container_tasks[0])) { 947 && get_deadline(t) < get_deadline(&container_tasks[0]) + get_rt_period(&container_tasks[0])) {
952 tsk_rt(t)->edfsc_params.will_remove = 1;
953 tsk_rt(t)->edfsc_params.move_to = NULL; 948 tsk_rt(t)->edfsc_params.move_to = NULL;
954 949
955 container = NULL; 950 container = NULL;
@@ -1070,13 +1065,26 @@ static enum hrtimer_restart container_boundary(struct hrtimer *timer)
1070 return HRTIMER_RESTART; 1065 return HRTIMER_RESTART;
1071} 1066}
1072 1067
1068/**
1069 * Fired when a task reaches its deadline and is pending deletion or migration
1070 */
1073static enum hrtimer_restart task_deadline_callback(struct hrtimer* timer) { 1071static enum hrtimer_restart task_deadline_callback(struct hrtimer* timer) {
1074 struct task_struct *t = container_of(timer, struct task_struct, edfsc_deadline_timer); 1072 struct task_struct *t = container_of(timer, struct task_struct, edfsc_deadline_timer);
1075 1073
1076 BUG_ON(is_container(t)); 1074 BUG_ON(is_container(t));
1077 1075 if (tsk_rt(t)->edfsc_params.move_to) {
1078 if (!is_released(t, litmus_clock()) || budget_exhausted(t)) { 1076 // Migrate here if the task is not late, otherwise migrate in job_complete
1079 remove_task(t); 1077 if (!is_released(t, litmus_clock()) || budget_exhausted(t))
1078 migrate_task(t);
1079 } else {
1080 // A move to NULL means deletion
1081 // HACK: See comment in edfsc_task_exit()
1082 if (tsk_rt(t)->task_params.cpu)
1083 c_remove_task(t);
1084 else
1085 g_remove_task(t);
1086 // Release our reference to the task struct
1087 put_task_struct(t);
1080 } 1088 }
1081 return HRTIMER_NORESTART; 1089 return HRTIMER_NORESTART;
1082} 1090}
@@ -1135,9 +1143,6 @@ static void edfsc_task_exit(struct task_struct* t)
1135 1143
1136 BUG_ON(is_container(t)); 1144 BUG_ON(is_container(t));
1137 raw_spin_lock_irqsave(&g_lock, flags); 1145 raw_spin_lock_irqsave(&g_lock, flags);
1138 // XXX: Superfluous. We never see `t` as one of our tasks again.
1139 tsk_rt(t)->edfsc_params.will_remove = 1;
1140
1141 1146
1142 // Remove this task from all members of its scheduling domain 1147 // Remove this task from all members of its scheduling domain
1143 unlink(t); 1148 unlink(t);
@@ -1178,10 +1183,22 @@ static void edfsc_task_exit(struct task_struct* t)
1178 unaccount_time = 0; 1183 unaccount_time = 0;
1179 } 1184 }
1180 1185
1186 /* Take out an extra reference on the task struct so that it's not freed until
1187 * the deadline boundary timer fires and we finish with it
1188 */
1189 get_task_struct(t);
1190 // Make it clear that this task is going away
1191 tsk_rt(t)->edfsc_params.move_to = NULL;
1192 /* HACK: Unfortunately, even though we hold a reference to the task struct,
1193 * LITMUS clears edfsc_params before the timer expires. task_params seem
1194 * untouched, so hijack task_params.cpu to indicate if this is a fixed task.
1195 */
1196 tsk_rt(t)->task_params.cpu = is_fixed(t);
1197
1181 if (unaccount_time == 0) 1198 if (unaccount_time == 0)
1182 remove_task(t); 1199 // Don't bother setting a zero-length timer - just skip straight to the callback
1200 task_deadline_callback(&t->edfsc_deadline_timer);
1183 else 1201 else
1184 // FIXME: This timer uses task struct data that may or may not exist at expiration
1185 hrtimer_start(&t->edfsc_deadline_timer, ns_to_ktime(unaccount_time), 1202 hrtimer_start(&t->edfsc_deadline_timer, ns_to_ktime(unaccount_time),
1186 HRTIMER_MODE_ABS_PINNED); 1203 HRTIMER_MODE_ABS_PINNED);
1187 1204