diff options
Diffstat (limited to 'litmus/edf_common.c')
-rw-r--r-- | litmus/edf_common.c | 264 |
1 files changed, 246 insertions, 18 deletions
diff --git a/litmus/edf_common.c b/litmus/edf_common.c index 5aca2934a7b5..441fbfddf0c2 100644 --- a/litmus/edf_common.c +++ b/litmus/edf_common.c | |||
@@ -12,6 +12,10 @@ | |||
12 | #include <litmus/sched_plugin.h> | 12 | #include <litmus/sched_plugin.h> |
13 | #include <litmus/sched_trace.h> | 13 | #include <litmus/sched_trace.h> |
14 | 14 | ||
15 | #ifdef CONFIG_LITMUS_NESTED_LOCKING | ||
16 | #include <litmus/locking.h> | ||
17 | #endif | ||
18 | |||
15 | #include <litmus/edf_common.h> | 19 | #include <litmus/edf_common.h> |
16 | 20 | ||
17 | #ifdef CONFIG_EDF_TIE_BREAK_LATENESS_NORM | 21 | #ifdef CONFIG_EDF_TIE_BREAK_LATENESS_NORM |
@@ -45,33 +49,158 @@ static inline long edf_hash(struct task_struct *t) | |||
45 | * | 49 | * |
46 | * both first and second may be NULL | 50 | * both first and second may be NULL |
47 | */ | 51 | */ |
48 | int edf_higher_prio(struct task_struct* first, | 52 | #ifdef CONFIG_LITMUS_NESTED_LOCKING |
49 | struct task_struct* second) | 53 | int __edf_higher_prio( |
54 | struct task_struct* first, comparison_mode_t first_mode, | ||
55 | struct task_struct* second, comparison_mode_t second_mode) | ||
56 | #else | ||
57 | int edf_higher_prio(struct task_struct* first, struct task_struct* second) | ||
58 | #endif | ||
50 | { | 59 | { |
51 | struct task_struct *first_task = first; | 60 | struct task_struct *first_task = first; |
52 | struct task_struct *second_task = second; | 61 | struct task_struct *second_task = second; |
53 | 62 | ||
54 | /* There is no point in comparing a task to itself. */ | 63 | /* There is no point in comparing a task to itself. */ |
55 | if (first && first == second) { | 64 | if (first && first == second) { |
56 | TRACE_TASK(first, | 65 | TRACE_CUR("WARNING: pointless edf priority comparison: %s/%d\n", first->comm, first->pid); |
57 | "WARNING: pointless edf priority comparison.\n"); | 66 | WARN_ON(1); |
58 | return 0; | 67 | return 0; |
59 | } | 68 | } |
60 | 69 | ||
61 | 70 | ||
62 | /* check for NULL tasks */ | 71 | /* check for NULL tasks */ |
63 | if (!first || !second) | 72 | if (!first || !second) { |
64 | return first && !second; | 73 | return first && !second; |
74 | } | ||
65 | 75 | ||
66 | #ifdef CONFIG_LITMUS_LOCKING | 76 | /* There is some goofy stuff in this code here. There are three subclasses |
77 | * within the SCHED_LITMUS scheduling class: | ||
78 | * 1) Auxiliary tasks: COTS helper threads from the application level that | ||
79 | * are forced to be real-time. | ||
80 | * 2) klmirqd interrupt threads: Litmus threaded interrupt handlers. | ||
81 | * 3) Normal Litmus tasks. | ||
82 | * | ||
83 | * At their base priorities, #3 > #2 > #1. However, #1 and #2 threads might | ||
84 | * inherit a priority from a task of #3. | ||
85 | * | ||
86 | * The code proceeds in the following manner: | ||
87 | * 1) Make aux and klmirqd threads with base-priorities have low priorities. | ||
88 | * 2) Determine effective priorities. | ||
89 | * 3) Perform priority comparison. Favor #3 over #1 and #2 in case of tie. | ||
90 | */ | ||
91 | |||
92 | |||
93 | #if defined(CONFIG_REALTIME_AUX_TASK_PRIORITY_BOOSTED) | ||
94 | /* run aux tasks at max priority */ | ||
95 | /* TODO: Actually use prio-boosting. */ | ||
96 | if (first->rt_param.is_aux_task != second->rt_param.is_aux_task) | ||
97 | { | ||
98 | return (first->rt_param.is_aux_task > second->rt_param.is_aux_task); | ||
99 | } | ||
100 | else if(first->rt_param.is_aux_task && second->rt_param.is_aux_task) | ||
101 | { | ||
102 | if(first->group_leader == second->group_leader) { | ||
103 | TRACE_CUR("aux tie break!\n"); // tie-break by BASE priority of the aux tasks | ||
104 | goto aux_tie_break; | ||
105 | } | ||
106 | first = first->group_leader; | ||
107 | second = second->group_leader; | ||
108 | } | ||
109 | #elif defined(CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE) | ||
110 | { | ||
111 | int first_lo_aux = first->rt_param.is_aux_task && !first->rt_param.inh_task; | ||
112 | int second_lo_aux = second->rt_param.is_aux_task && !second->rt_param.inh_task; | ||
113 | |||
114 | /* prioritize aux tasks without inheritance below real-time tasks */ | ||
115 | if (first_lo_aux || second_lo_aux) { | ||
116 | // one of these is an aux task without inheritance. | ||
117 | if(first_lo_aux && second_lo_aux) { | ||
118 | TRACE_CUR("aux tie break!\n"); // tie-break by BASE priority of the aux tasks | ||
119 | goto aux_tie_break; | ||
120 | } | ||
121 | else { | ||
122 | |||
123 | // make the aux thread lowest priority real-time task | ||
124 | int temp = 0; | ||
125 | if (first_lo_aux && is_realtime(second)) { | ||
126 | // temp = 0; | ||
127 | } | ||
128 | else if(second_lo_aux && is_realtime(first)) { | ||
129 | temp = 1; | ||
130 | } | ||
131 | TRACE_CUR("%s/%d >> %s/%d --- %d\n", first->comm, first->pid, second->comm, second->pid, temp); | ||
132 | return temp; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | if (first->rt_param.is_aux_task && second->rt_param.is_aux_task && | ||
137 | first->rt_param.inh_task == second->rt_param.inh_task) { | ||
138 | // inh_task is !NULL for both tasks since neither was a lo_aux task. | ||
139 | // Both aux tasks inherit from the same task, so tie-break | ||
140 | // by base priority of the aux tasks. | ||
141 | TRACE_CUR("aux tie break!\n"); | ||
142 | goto aux_tie_break; | ||
143 | } | ||
144 | } | ||
145 | #endif | ||
146 | |||
147 | #ifdef CONFIG_LITMUS_SOFTIRQD | ||
148 | { | ||
149 | int first_lo_klmirqd = first->rt_param.is_interrupt_thread && !first->rt_param.inh_task; | ||
150 | int second_lo_klmirqd = second->rt_param.is_interrupt_thread && !second->rt_param.inh_task; | ||
151 | |||
152 | /* prioritize aux tasks without inheritance below real-time tasks */ | ||
153 | if (first_lo_klmirqd || second_lo_klmirqd) { | ||
154 | // one of these is an klmirqd thread without inheritance. | ||
155 | if(first_lo_klmirqd && second_lo_klmirqd) { | ||
156 | TRACE_CUR("klmirqd tie break!\n"); // tie-break by BASE priority of the aux tasks | ||
157 | goto klmirqd_tie_break; | ||
158 | } | ||
159 | else { | ||
160 | // make the klmirqd thread the lowest-priority real-time task | ||
161 | // but (above low-prio aux tasks and Linux tasks) | ||
162 | int temp = 0; | ||
163 | if (first_lo_klmirqd && is_realtime(second)) { | ||
164 | // temp = 0; | ||
165 | } | ||
166 | else if(second_lo_klmirqd && is_realtime(first)) { | ||
167 | temp = 1; | ||
168 | } | ||
169 | TRACE_CUR("%s/%d >> %s/%d --- %d\n", first->comm, first->pid, second->comm, second->pid, temp); | ||
170 | return temp; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | if (first->rt_param.is_interrupt_thread && second->rt_param.is_interrupt_thread && | ||
175 | first->rt_param.inh_task == second->rt_param.inh_task) { | ||
176 | // inh_task is !NULL for both tasks since neither was a lo_klmirqd task. | ||
177 | // Both klmirqd tasks inherit from the same task, so tie-break | ||
178 | // by base priority of the klmirqd tasks. | ||
179 | TRACE_CUR("klmirqd tie break!\n"); | ||
180 | goto klmirqd_tie_break; | ||
181 | } | ||
182 | } | ||
183 | #endif | ||
67 | 184 | ||
68 | /* Check for inherited priorities. Change task | 185 | |
186 | #ifdef CONFIG_LITMUS_LOCKING | ||
187 | /* Check for EFFECTIVE priorities. Change task | ||
69 | * used for comparison in such a case. | 188 | * used for comparison in such a case. |
70 | */ | 189 | */ |
71 | if (unlikely(first->rt_param.inh_task)) | 190 | if (unlikely(first->rt_param.inh_task) |
191 | #ifdef CONFIG_LITMUS_NESTED_LOCKING | ||
192 | && (first_mode == EFFECTIVE) | ||
193 | #endif | ||
194 | ) { | ||
72 | first_task = first->rt_param.inh_task; | 195 | first_task = first->rt_param.inh_task; |
73 | if (unlikely(second->rt_param.inh_task)) | 196 | } |
197 | if (unlikely(second->rt_param.inh_task) | ||
198 | #ifdef CONFIG_LITMUS_NESTED_LOCKING | ||
199 | && (second_mode == EFFECTIVE) | ||
200 | #endif | ||
201 | ) { | ||
74 | second_task = second->rt_param.inh_task; | 202 | second_task = second->rt_param.inh_task; |
203 | } | ||
75 | 204 | ||
76 | /* Check for priority boosting. Tie-break by start of boosting. | 205 | /* Check for priority boosting. Tie-break by start of boosting. |
77 | */ | 206 | */ |
@@ -79,17 +208,31 @@ int edf_higher_prio(struct task_struct* first, | |||
79 | /* first_task is boosted, how about second_task? */ | 208 | /* first_task is boosted, how about second_task? */ |
80 | if (!is_priority_boosted(second_task) || | 209 | if (!is_priority_boosted(second_task) || |
81 | lt_before(get_boost_start(first_task), | 210 | lt_before(get_boost_start(first_task), |
82 | get_boost_start(second_task))) | 211 | get_boost_start(second_task))) { |
83 | return 1; | 212 | return 1; |
84 | else | 213 | } |
214 | else { | ||
85 | return 0; | 215 | return 0; |
86 | } else if (unlikely(is_priority_boosted(second_task))) | 216 | } |
217 | } | ||
218 | else if (unlikely(is_priority_boosted(second_task))) { | ||
87 | /* second_task is boosted, first is not*/ | 219 | /* second_task is boosted, first is not*/ |
88 | return 0; | 220 | return 0; |
221 | } | ||
222 | |||
223 | #endif | ||
89 | 224 | ||
225 | #ifdef CONFIG_REALTIME_AUX_TASKS | ||
226 | aux_tie_break: | ||
227 | #endif | ||
228 | #ifdef CONFIG_LITMUS_SOFTIRQD | ||
229 | klmirqd_tie_break: | ||
90 | #endif | 230 | #endif |
91 | 231 | ||
92 | if (earlier_deadline(first_task, second_task)) { | 232 | if (!is_realtime(second_task)) { |
233 | return 1; | ||
234 | } | ||
235 | else if (earlier_deadline(first_task, second_task)) { | ||
93 | return 1; | 236 | return 1; |
94 | } | 237 | } |
95 | else if (get_deadline(first_task) == get_deadline(second_task)) { | 238 | else if (get_deadline(first_task) == get_deadline(second_task)) { |
@@ -98,7 +241,6 @@ int edf_higher_prio(struct task_struct* first, | |||
98 | */ | 241 | */ |
99 | int pid_break; | 242 | int pid_break; |
100 | 243 | ||
101 | |||
102 | #if defined(CONFIG_EDF_TIE_BREAK_LATENESS) | 244 | #if defined(CONFIG_EDF_TIE_BREAK_LATENESS) |
103 | /* Tie break by lateness. Jobs with greater lateness get | 245 | /* Tie break by lateness. Jobs with greater lateness get |
104 | * priority. This should spread tardiness across all tasks, | 246 | * priority. This should spread tardiness across all tasks, |
@@ -154,18 +296,104 @@ int edf_higher_prio(struct task_struct* first, | |||
154 | return 1; | 296 | return 1; |
155 | } | 297 | } |
156 | else if (first_task->pid == second_task->pid) { | 298 | else if (first_task->pid == second_task->pid) { |
157 | /* If the PIDs are the same then the task with the | 299 | #ifdef CONFIG_LITMUS_SOFTIRQD |
158 | * inherited priority wins. | 300 | if (first_task->rt_param.is_interrupt_thread < second_task->rt_param.is_interrupt_thread) { |
159 | */ | 301 | return 1; |
160 | if (!second->rt_param.inh_task) { | 302 | } |
303 | else if (first_task->rt_param.is_interrupt_thread == second_task->rt_param.is_interrupt_thread) { | ||
304 | #endif | ||
305 | |||
306 | #if defined(CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE) | ||
307 | if (tsk_rt(first)->is_aux_task < tsk_rt(second)->is_aux_task) { | ||
161 | return 1; | 308 | return 1; |
162 | } | 309 | } |
310 | else if (tsk_rt(first)->is_aux_task == tsk_rt(second)->is_aux_task) { | ||
311 | #endif | ||
312 | |||
313 | /* Something could be wrong if you get this far. */ | ||
314 | if (unlikely(first->rt_param.inh_task == second->rt_param.inh_task)) { | ||
315 | /* Both tasks have the same inherited priority. | ||
316 | * Likely in a bug-condition. | ||
317 | */ | ||
318 | if (first->pid < second->pid) { | ||
319 | return 1; | ||
320 | } | ||
321 | else if (first->pid == second->pid) { | ||
322 | //WARN_ON(1); | ||
323 | } | ||
324 | } | ||
325 | else { | ||
326 | /* At least one task must inherit */ | ||
327 | BUG_ON(!first->rt_param.inh_task && | ||
328 | !second->rt_param.inh_task); | ||
329 | |||
330 | /* The task withOUT the inherited priority wins. */ | ||
331 | if (second->rt_param.inh_task) { | ||
332 | /* | ||
333 | * common with aux tasks. | ||
334 | TRACE_CUR("unusual comparison: " | ||
335 | "first = %s/%d first_task = %s/%d " | ||
336 | "second = %s/%d second_task = %s/%d\n", | ||
337 | first->comm, first->pid, | ||
338 | (first->rt_param.inh_task) ? first->rt_param.inh_task->comm : "(nil)", | ||
339 | (first->rt_param.inh_task) ? first->rt_param.inh_task->pid : 0, | ||
340 | second->comm, second->pid, | ||
341 | (second->rt_param.inh_task) ? second->rt_param.inh_task->comm : "(nil)", | ||
342 | (second->rt_param.inh_task) ? second->rt_param.inh_task->pid : 0); | ||
343 | */ | ||
344 | return 1; | ||
345 | } | ||
346 | } | ||
347 | #if defined(CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE) | ||
348 | } | ||
349 | #endif | ||
350 | |||
351 | #ifdef CONFIG_LITMUS_SOFTIRQD | ||
352 | } | ||
353 | #endif | ||
354 | |||
163 | } | 355 | } |
164 | } | 356 | } |
165 | } | 357 | } |
358 | |||
166 | return 0; /* fall-through. prio(second_task) > prio(first_task) */ | 359 | return 0; /* fall-through. prio(second_task) > prio(first_task) */ |
167 | } | 360 | } |
168 | 361 | ||
362 | |||
363 | #ifdef CONFIG_LITMUS_NESTED_LOCKING | ||
364 | int edf_higher_prio(struct task_struct* first, struct task_struct* second) | ||
365 | { | ||
366 | return __edf_higher_prio(first, EFFECTIVE, second, EFFECTIVE); | ||
367 | } | ||
368 | |||
369 | int edf_max_heap_order(struct binheap_node *a, struct binheap_node *b) | ||
370 | { | ||
371 | struct nested_info *l_a = (struct nested_info *)binheap_entry(a, struct nested_info, hp_binheap_node); | ||
372 | struct nested_info *l_b = (struct nested_info *)binheap_entry(b, struct nested_info, hp_binheap_node); | ||
373 | |||
374 | return __edf_higher_prio(l_a->hp_waiter_eff_prio, EFFECTIVE, l_b->hp_waiter_eff_prio, EFFECTIVE); | ||
375 | } | ||
376 | |||
377 | int edf_min_heap_order(struct binheap_node *a, struct binheap_node *b) | ||
378 | { | ||
379 | return edf_max_heap_order(b, a); // swap comparison | ||
380 | } | ||
381 | |||
382 | int edf_max_heap_base_priority_order(struct binheap_node *a, struct binheap_node *b) | ||
383 | { | ||
384 | struct nested_info *l_a = (struct nested_info *)binheap_entry(a, struct nested_info, hp_binheap_node); | ||
385 | struct nested_info *l_b = (struct nested_info *)binheap_entry(b, struct nested_info, hp_binheap_node); | ||
386 | |||
387 | return __edf_higher_prio(l_a->hp_waiter_eff_prio, BASE, l_b->hp_waiter_eff_prio, BASE); | ||
388 | } | ||
389 | |||
390 | int edf_min_heap_base_priority_order(struct binheap_node *a, struct binheap_node *b) | ||
391 | { | ||
392 | return edf_max_heap_base_priority_order(b, a); // swap comparison | ||
393 | } | ||
394 | #endif | ||
395 | |||
396 | |||
169 | int edf_ready_order(struct bheap_node* a, struct bheap_node* b) | 397 | int edf_ready_order(struct bheap_node* a, struct bheap_node* b) |
170 | { | 398 | { |
171 | return edf_higher_prio(bheap2task(a), bheap2task(b)); | 399 | return edf_higher_prio(bheap2task(a), bheap2task(b)); |