aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/edf_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/edf_common.c')
-rw-r--r--litmus/edf_common.c264
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 */
48int edf_higher_prio(struct task_struct* first, 52#ifdef CONFIG_LITMUS_NESTED_LOCKING
49 struct task_struct* second) 53int __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
57int 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
226aux_tie_break:
227#endif
228#ifdef CONFIG_LITMUS_SOFTIRQD
229klmirqd_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
364int edf_higher_prio(struct task_struct* first, struct task_struct* second)
365{
366 return __edf_higher_prio(first, EFFECTIVE, second, EFFECTIVE);
367}
368
369int 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
377int 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
382int 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
390int 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
169int edf_ready_order(struct bheap_node* a, struct bheap_node* b) 397int 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));