diff options
author | Zelin Tong <ztong@ludwig.cs.unc.edu> | 2020-03-04 13:54:43 -0500 |
---|---|---|
committer | Zelin Tong <ztong@ludwig.cs.unc.edu> | 2020-03-04 13:54:43 -0500 |
commit | ade4ca95d6619e92b348259395a30d978842a77a (patch) | |
tree | 943dcc02954e3e57f642dfca2e737982cc4bab37 | |
parent | a3591651158fb7839bf5b7a84620d5f3fe31f326 (diff) | |
parent | 1f4fabf52690ef8f84275b720b25e7a0adc74440 (diff) |
Merge branch 'edfsc-wip' of rtsrv.cs.unc.edu:/public/litmus-rt-edfsc into edfsc-wip
-rw-r--r-- | litmus/sched_edfsc.c | 94 |
1 files changed, 57 insertions, 37 deletions
diff --git a/litmus/sched_edfsc.c b/litmus/sched_edfsc.c index 14a775453a78..ea1b308667c7 100644 --- a/litmus/sched_edfsc.c +++ b/litmus/sched_edfsc.c | |||
@@ -1001,52 +1001,72 @@ static void edfsc_task_block(struct task_struct *t) | |||
1001 | // TODO | 1001 | // TODO |
1002 | } | 1002 | } |
1003 | 1003 | ||
1004 | /** | ||
1005 | * This is called by LITMUS before our task is switched to another scheduler | ||
1006 | * During task termination (do_exit()), LITMUS first switches the scheduler | ||
1007 | * to SCHED_FIFO before running the normal Linux task termination proceedure. | ||
1008 | * After we return from this, `t` may or may not still exist. So we should have | ||
1009 | * no outstanding handles to any part of the task struct afer this point. | ||
1010 | */ | ||
1004 | static void edfsc_task_exit(struct task_struct* t) | 1011 | static void edfsc_task_exit(struct task_struct* t) |
1005 | { | 1012 | { |
1006 | unsigned long flags; | 1013 | unsigned long flags; |
1007 | lt_t now; | 1014 | lt_t now, unaccount_time = 0; |
1008 | raw_spin_lock_irqsave(&g_lock, flags); | 1015 | cpu_entry_t* entry; |
1009 | now = litmus_clock(); | 1016 | |
1010 | 1017 | ||
1018 | BUG_ON(is_container(t)); | ||
1019 | raw_spin_lock_irqsave(&g_lock, flags); | ||
1020 | // XXX: Superfluous. We never see `t` as one of our tasks again. | ||
1011 | tsk_rt(t)->edfsc_params.will_remove = 1; | 1021 | tsk_rt(t)->edfsc_params.will_remove = 1; |
1012 | 1022 | ||
1013 | // If the task has no pending job | 1023 | |
1014 | if (!is_released(t, now)) { | 1024 | // Remove this task from all members of its scheduling domain |
1015 | // If the deadline of its last job is in the future, reserve the | 1025 | unlink(t); |
1016 | // utilization until its deadline | 1026 | if (is_queued(t)) { |
1017 | if (lt_after(tsk_rt(t)->edfsc_params.prev_deadline, now)) { | 1027 | remove(tsk_rt(t)->domain, t); |
1018 | if (is_queued(t)) | 1028 | } else if (is_fixed(t)) { |
1019 | remove(tsk_rt(t)->domain, t); | 1029 | // If we're fixed and not on the ready queues, we should be currently running |
1020 | //hrtimer_start(&(tsk_rt(t)->edfsc_params.deadline_timer), | 1030 | BUG_ON(((cont_domain_t*)tsk_rt(t)->domain)->scheduled != t); |
1021 | // ns_to_ktime(tsk_rt(t)->edfsc_params.prev_deadline), | 1031 | BUG_ON(t != current); |
1022 | // HRTIMER_MODE_ABS_PINNED); | 1032 | ((cont_domain_t*)tsk_rt(t)->domain)->scheduled = NULL; |
1023 | hrtimer_start(&t->edfsc_deadline_timer, | ||
1024 | ns_to_ktime(tsk_rt(t)->edfsc_params.prev_deadline), | ||
1025 | HRTIMER_MODE_ABS_PINNED); | ||
1026 | // Else remove it and we're done | ||
1027 | } else { | ||
1028 | if (is_queued(t)) | ||
1029 | remove(tsk_rt(t)->domain, t); | ||
1030 | // XXX not sure if this needs an additional condition guarding it | ||
1031 | remove_task(t); | ||
1032 | } | ||
1033 | // If the task has a pending job, we can immediatly stop LITMUS from | ||
1034 | // scheduling it but still have to reserve its utilization until the deadline | ||
1035 | } else { | 1033 | } else { |
1036 | //reserve the utilization, but remove it from being scheduled by litmus | 1034 | // We're in the global domain and not on the ready queues, so we must be running |
1037 | unlink(t); | 1035 | BUG_ON(t != current); |
1038 | if (tsk_rt(t)->scheduled_on != NO_CPU) { | 1036 | BUG_ON(tsk_rt(t)->scheduled_on == NO_CPU); |
1039 | (&per_cpu(edfsc_cpu_entries, tsk_rt(t)->scheduled_on))->scheduled = NULL; | 1037 | entry = &per_cpu(edfsc_cpu_entries, tsk_rt(t)->scheduled_on); |
1040 | tsk_rt(t)->scheduled_on = NO_CPU; | 1038 | BUG_ON(entry->scheduled != t); |
1041 | } | 1039 | entry->scheduled = NULL; |
1042 | //hrtimer_start(&(tsk_rt(t)->edfsc_params.deadline_timer), | 1040 | } |
1043 | // ns_to_ktime(get_deadline(t)), | 1041 | |
1044 | // HRTIMER_MODE_ABS_PINNED); | 1042 | /* To preserve EDF-sc scheduling invariants, we can only release a task's |
1045 | hrtimer_start(&t->edfsc_deadline_timer, | 1043 | * utilization at the greater of the period or deadline boundry. Thus, here |
1046 | ns_to_ktime(get_deadline(t)), | 1044 | * we schedule a timer to handle this unaccounting of utilization. |
1047 | HRTIMER_MODE_ABS_PINNED); | 1045 | */ |
1046 | now = litmus_clock(); | ||
1047 | if (is_released(t, now)) { | ||
1048 | /* If a task has already been released, no future jobs are pending and we can | ||
1049 | * just unaccount at the current deadline. | ||
1050 | */ | ||
1051 | unaccount_time = get_deadline(t); | ||
1052 | } else { | ||
1053 | /* If the task has yet to be released, but we still haven't reached the | ||
1054 | * deadline of its last-finished job, wait for that deadline. Otherwise | ||
1055 | * we're after a deadline and before a release, so just remove now. | ||
1056 | */ | ||
1057 | if (lt_after(tsk_rt(t)->edfsc_params.prev_deadline, now)) | ||
1058 | unaccount_time = tsk_rt(t)->edfsc_params.prev_deadline; | ||
1059 | else | ||
1060 | unaccount_time = 0; | ||
1048 | } | 1061 | } |
1049 | 1062 | ||
1063 | if (unaccount_time == 0) | ||
1064 | remove_task(t); | ||
1065 | else | ||
1066 | // FIXME: This timer uses task struct data that may or may not exist at expiration | ||
1067 | hrtimer_start(&t->edfsc_deadline_timer, ns_to_ktime(unaccount_time), | ||
1068 | HRTIMER_MODE_ABS_PINNED); | ||
1069 | |||
1050 | raw_spin_unlock_irqrestore(&g_lock, flags); | 1070 | raw_spin_unlock_irqrestore(&g_lock, flags); |
1051 | } | 1071 | } |
1052 | 1072 | ||