diff options
author | Joshua Bakita <jbakita@cs.unc.edu> | 2020-03-07 20:20:17 -0500 |
---|---|---|
committer | Joshua Bakita <jbakita@cs.unc.edu> | 2020-03-07 20:20:17 -0500 |
commit | fbcf3074b978275274270dcbaaf40da62b6f0b69 (patch) | |
tree | b1bd19115eacaf64b75e553bd1fecca1735672c2 | |
parent | f523a230da7c2813b03f2e9e1d9d2e8848987052 (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.h | 1 | ||||
-rw-r--r-- | litmus/sched_edfsc.c | 83 |
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 | ||
442 | static 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 | */ | ||
447 | static 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 | */ | ||
1073 | static enum hrtimer_restart task_deadline_callback(struct hrtimer* timer) { | 1071 | static 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 | ||