aboutsummaryrefslogtreecommitdiffstats
path: root/litmus
diff options
context:
space:
mode:
authorJoshua Bakita <jbakita@cs.unc.edu>2020-03-04 11:01:27 -0500
committerJoshua Bakita <jbakita@cs.unc.edu>2020-03-04 11:01:27 -0500
commit1f4fabf52690ef8f84275b720b25e7a0adc74440 (patch)
tree76cf747b27343f0a6e24280ffdeb72bf93070b82 /litmus
parentf6e8a4fe3a975fdbf3e3137d2debfaa84631a6cb (diff)
Rewrite edfsc_task_exit(). Task termination now works.
Correcting the deadline timer to not touch potentially invalid memory is still TODO.
Diffstat (limited to 'litmus')
-rw-r--r--litmus/sched_edfsc.c92
1 files changed, 55 insertions, 37 deletions
diff --git a/litmus/sched_edfsc.c b/litmus/sched_edfsc.c
index fff134e5f1bc..a3452662ad23 100644
--- a/litmus/sched_edfsc.c
+++ b/litmus/sched_edfsc.c
@@ -1009,53 +1009,71 @@ static void edfsc_task_block(struct task_struct *t)
1009 // TODO 1009 // TODO
1010} 1010}
1011 1011
1012/**
1013 * This is called by LITMUS before our task is switched to another scheduler
1014 * During task termination (do_exit()), LITMUS first switches the scheduler
1015 * to SCHED_FIFO before running the normal Linux task termination proceedure.
1016 * After we return from this, `t` may or may not still exist. So we should have
1017 * no outstanding handles to any part of the task struct afer this point.
1018 */
1012static void edfsc_task_exit(struct task_struct* t) 1019static void edfsc_task_exit(struct task_struct* t)
1013{ 1020{
1014 unsigned long flags; 1021 unsigned long flags;
1015 lt_t now; 1022 lt_t now, unaccount_time = 0;
1023 cpu_entry_t* entry;
1024
1016 printk("edfsc_task_exit\n"); 1025 printk("edfsc_task_exit\n");
1026 BUG_ON(is_container(t));
1017 raw_spin_lock_irqsave(&g_lock, flags); 1027 raw_spin_lock_irqsave(&g_lock, flags);
1018 now = litmus_clock(); 1028 // XXX: Superfluous. We never see `t` as one of our tasks again.
1019
1020 tsk_rt(t)->edfsc_params.will_remove = 1; 1029 tsk_rt(t)->edfsc_params.will_remove = 1;
1021 1030
1022 // If the task has no pending job 1031 // Remove this task from all members of its scheduling domain
1023 if (!is_released(t, now)) { 1032 unlink(t);
1024 // If the deadline of its last job is in the future, reserve the 1033 if (is_queued(t)) {
1025 // utilization until its deadline 1034 remove(tsk_rt(t)->domain, t);
1026 if (lt_after(tsk_rt(t)->edfsc_params.prev_deadline, now)) { 1035 } else if (is_fixed(t)) {
1027 if (is_queued(t)) 1036 // If we're fixed and not on the ready queues, we should be currently running
1028 remove(tsk_rt(t)->domain, t); 1037 BUG_ON(((cont_domain_t*)tsk_rt(t)->domain)->scheduled != t);
1029 //hrtimer_start(&(tsk_rt(t)->edfsc_params.deadline_timer), 1038 BUG_ON(t != current);
1030 // ns_to_ktime(tsk_rt(t)->edfsc_params.prev_deadline), 1039 ((cont_domain_t*)tsk_rt(t)->domain)->scheduled = NULL;
1031 // HRTIMER_MODE_ABS_PINNED);
1032 hrtimer_start(&t->edfsc_deadline_timer,
1033 ns_to_ktime(tsk_rt(t)->edfsc_params.prev_deadline),
1034 HRTIMER_MODE_ABS_PINNED);
1035 // Else remove it and we're done
1036 } else {
1037 if (is_queued(t))
1038 remove(tsk_rt(t)->domain, t);
1039 // XXX not sure if this needs an additional condition guarding it
1040 remove_task(t);
1041 }
1042 // If the task has a pending job, we can immediatly stop LITMUS from
1043 // scheduling it but still have to reserve its utilization until the deadline
1044 } else { 1040 } else {
1045 //reserve the utilization, but remove it from being scheduled by litmus 1041 // We're in the global domain and not on the ready queues, so we must be running
1046 unlink(t); 1042 BUG_ON(t != current);
1047 if (tsk_rt(t)->scheduled_on != NO_CPU) { 1043 BUG_ON(tsk_rt(t)->scheduled_on == NO_CPU);
1048 (&per_cpu(edfsc_cpu_entries, tsk_rt(t)->scheduled_on))->scheduled = NULL; 1044 entry = &per_cpu(edfsc_cpu_entries, tsk_rt(t)->scheduled_on);
1049 tsk_rt(t)->scheduled_on = NO_CPU; 1045 BUG_ON(entry->scheduled != t);
1050 } 1046 entry->scheduled = NULL;
1051 //hrtimer_start(&(tsk_rt(t)->edfsc_params.deadline_timer),
1052 // ns_to_ktime(get_deadline(t)),
1053 // HRTIMER_MODE_ABS_PINNED);
1054 hrtimer_start(&t->edfsc_deadline_timer,
1055 ns_to_ktime(get_deadline(t)),
1056 HRTIMER_MODE_ABS_PINNED);
1057 } 1047 }
1058 1048
1049 /* To preserve EDF-sc scheduling invariants, we can only release a task's
1050 * utilization at the greater of the period or deadline boundry. Thus, here
1051 * we schedule a timer to handle this unaccounting of utilization.
1052 */
1053 now = litmus_clock();
1054 if (is_released(t, now)) {
1055 /* If a task has already been released, no future jobs are pending and we can
1056 * just unaccount at the current deadline.
1057 */
1058 unaccount_time = get_deadline(t);
1059 } else {
1060 /* If the task has yet to be released, but we still haven't reached the
1061 * deadline of its last-finished job, wait for that deadline. Otherwise
1062 * we're after a deadline and before a release, so just remove now.
1063 */
1064 if (lt_after(tsk_rt(t)->edfsc_params.prev_deadline, now))
1065 unaccount_time = tsk_rt(t)->edfsc_params.prev_deadline;
1066 else
1067 unaccount_time = 0;
1068 }
1069
1070 if (unaccount_time == 0)
1071 remove_task(t);
1072 else
1073 // FIXME: This timer uses task struct data that may or may not exist at expiration
1074 hrtimer_start(&t->edfsc_deadline_timer, ns_to_ktime(unaccount_time),
1075 HRTIMER_MODE_ABS_PINNED);
1076
1059 raw_spin_unlock_irqrestore(&g_lock, flags); 1077 raw_spin_unlock_irqrestore(&g_lock, flags);
1060} 1078}
1061 1079