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 | ||
