diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2011-04-04 03:58:25 -0400 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2011-04-04 03:58:25 -0400 |
commit | 010daf8f84dc0bb196c0d2f3f8fb8255e6d19b8b (patch) | |
tree | b0cee758b3bf4e0b13fc9d1a2cfb6996508ed39d /litmus/sched_edf_hsb.c | |
parent | 080b5d97e8407994a1c697a1b5929ce3209db03c (diff) |
slack stealing
Diffstat (limited to 'litmus/sched_edf_hsb.c')
-rw-r--r-- | litmus/sched_edf_hsb.c | 685 |
1 files changed, 525 insertions, 160 deletions
diff --git a/litmus/sched_edf_hsb.c b/litmus/sched_edf_hsb.c index 12abe3def2d3..4b2c58ec6b75 100644 --- a/litmus/sched_edf_hsb.c +++ b/litmus/sched_edf_hsb.c | |||
@@ -16,6 +16,10 @@ | |||
16 | * admit_[hrt|be]_server | 16 | * admit_[hrt|be]_server |
17 | * | 17 | * |
18 | * TODO BE SERVER TASK PREEMPTGION A;SDIFHSAKEUHFLKH | 18 | * TODO BE SERVER TASK PREEMPTGION A;SDIFHSAKEUHFLKH |
19 | * TODO BE server heap needed? | ||
20 | * TODO move slack completion into release | ||
21 | * TODO fix concurrent arms | ||
22 | * TODO slack and BE servers | ||
19 | * | 23 | * |
20 | */ | 24 | */ |
21 | #include <linux/module.h> | 25 | #include <linux/module.h> |
@@ -34,7 +38,6 @@ | |||
34 | #include <litmus/edf_common.h> | 38 | #include <litmus/edf_common.h> |
35 | #include <litmus/sched_trace.h> | 39 | #include <litmus/sched_trace.h> |
36 | #include <litmus/servers.h> | 40 | #include <litmus/servers.h> |
37 | |||
38 | #define DEBUG_EDF_HSB | 41 | #define DEBUG_EDF_HSB |
39 | 42 | ||
40 | /* DOES NOT WORK */ | 43 | /* DOES NOT WORK */ |
@@ -43,6 +46,7 @@ | |||
43 | #define BE_PROC_NAME "be_servers" | 46 | #define BE_PROC_NAME "be_servers" |
44 | #define HRT_PROC_NAME "hrt_servers" | 47 | #define HRT_PROC_NAME "hrt_servers" |
45 | #define BE_SERVER_BASE 100 | 48 | #define BE_SERVER_BASE 100 |
49 | #define SLACK_MIN NSEC_PER_MSEC | ||
46 | 50 | ||
47 | #define TIME(x) \ | 51 | #define TIME(x) \ |
48 | ({lt_t y = x; \ | 52 | ({lt_t y = x; \ |
@@ -67,11 +71,21 @@ atomic_t servers_running = ATOMIC_INIT(0); | |||
67 | #define TRACE_TASK_SUB(t, fmt, args...) \ | 71 | #define TRACE_TASK_SUB(t, fmt, args...) \ |
68 | TRACE_SUB("(%s/%d:%d) " fmt, (t)->comm, (t)->pid, \ | 72 | TRACE_SUB("(%s/%d:%d) " fmt, (t)->comm, (t)->pid, \ |
69 | (t)->rt_param.job_params.job_no, ##args) | 73 | (t)->rt_param.job_params.job_no, ##args) |
74 | #define TRACE_SERVER_SUB(s, fmt, args...) \ | ||
75 | TRACE_SUB(SERVER_FMT " " fmt, SERVER_ARGS(s), ##args) | ||
70 | #else | 76 | #else |
71 | #define TRACE_SUB(fmt, args...) | 77 | #define TRACE_SUB(fmt, args...) |
72 | #define TRACE_TASK_SUB(t, fmt, args...) | 78 | #define TRACE_TASK_SUB(t, fmt, args...) |
79 | #define TRACE_SERVER_SUB(s, fmt, args...) | ||
73 | #endif | 80 | #endif |
74 | 81 | ||
82 | typedef enum { | ||
83 | S_HRT, | ||
84 | S_SRT, | ||
85 | S_BE, | ||
86 | S_SLACK | ||
87 | } server_type_t; | ||
88 | |||
75 | typedef struct { | 89 | typedef struct { |
76 | server_t server; | 90 | server_t server; |
77 | rt_domain_t hrt_domain; /* EDF for HRT tasks assigned here */ | 91 | rt_domain_t hrt_domain; /* EDF for HRT tasks assigned here */ |
@@ -108,6 +122,9 @@ static server_domain_t server_domain; /* Useful tools for server scheduling */ | |||
108 | static struct list_head be_servers; /* All BE servers */ | 122 | static struct list_head be_servers; /* All BE servers */ |
109 | static struct bheap be_ready_servers; /* Runnable BE servers */ | 123 | static struct bheap be_ready_servers; /* Runnable BE servers */ |
110 | 124 | ||
125 | static struct list_head slack_queue; | ||
126 | static struct list_head slack_candidates; | ||
127 | |||
111 | static int release_master; /* CPU which will release tasks and global servers */ | 128 | static int release_master; /* CPU which will release tasks and global servers */ |
112 | 129 | ||
113 | static struct proc_dir_entry *edf_hsb_proc_dir = NULL; | 130 | static struct proc_dir_entry *edf_hsb_proc_dir = NULL; |
@@ -117,9 +134,194 @@ static struct sched_plugin edf_hsb_plugin __cacheline_aligned_in_smp; | |||
117 | #define task_sched_entry(task) (&per_cpu(cpu_entries, task_cpu(task))) | 134 | #define task_sched_entry(task) (&per_cpu(cpu_entries, task_cpu(task))) |
118 | #define task_linked_entry(task) (&per_cpu(cpu_entries, task->rt_param.linked_on)) | 135 | #define task_linked_entry(task) (&per_cpu(cpu_entries, task->rt_param.linked_on)) |
119 | #define task_job_no(task) (tsk_rt(task)->job_params.job_no) | 136 | #define task_job_no(task) (tsk_rt(task)->job_params.job_no) |
137 | #define task_srt_server(task) ((server_t*)tsk_rt(task)->plugin_data) | ||
138 | #define task_slack_server(task) ((server_t*)tsk_rt(task)->slack_server) | ||
120 | #define global_lock (&srt_domain.ready_lock) | 139 | #define global_lock (&srt_domain.ready_lock) |
121 | #define is_active_plugin (litmus == &edf_hsb_plugin) | 140 | #define is_active_plugin (litmus == &edf_hsb_plugin) |
122 | 141 | ||
142 | static inline int head_in_list(struct list_head *list) | ||
143 | { | ||
144 | if ((list->next == list->prev && list->prev == list) || | ||
145 | (list->next == LIST_POISON1 && list->prev == LIST_POISON2)) | ||
146 | return 0; | ||
147 | else | ||
148 | return 1; | ||
149 | } | ||
150 | |||
151 | /* In the next methods check to see if have donated. If so, do what? | ||
152 | * Server_stop. in check for hrt, need to make sure a check for global is | ||
153 | * called. in the other one, just need to make sure we unlink and crap and | ||
154 | * then call for it again. | ||
155 | * What happens if an srt is released that is scheduled? | ||
156 | * Then the effective deadline will mark it. | ||
157 | */ | ||
158 | static server_t* next_eligible_slack(void) | ||
159 | { | ||
160 | server_t *next_slack = NULL, *donator; | ||
161 | lt_t now = litmus_clock(); | ||
162 | |||
163 | while (!list_empty(&slack_queue)) { | ||
164 | next_slack = list_entry(slack_queue.next, server_t, list); | ||
165 | |||
166 | if (lt_after(next_slack->deadline, now) && | ||
167 | next_slack->budget > SLACK_MIN) { | ||
168 | break; | ||
169 | } else { | ||
170 | /* Slack has expired or has too little time */ | ||
171 | TRACE_SUB("slack " SERVER_FMT " has expired", | ||
172 | SERVER_ARGS(next_slack)); | ||
173 | sched_trace_action(NULL, 7); | ||
174 | |||
175 | list_del(&next_slack->list); | ||
176 | donator = (server_t*)next_slack->data; | ||
177 | donator->data = NULL; | ||
178 | server_destroy(next_slack); | ||
179 | kfree(next_slack); | ||
180 | |||
181 | next_slack = NULL; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | if (next_slack) | ||
186 | TRACE_SERVER_SUB(next_slack, "found eligible slack, " | ||
187 | "now: %llu, dead: %llu", now, | ||
188 | next_slack->deadline); | ||
189 | else | ||
190 | TRACE_SUB("no eligible slack"); | ||
191 | |||
192 | return next_slack; | ||
193 | } | ||
194 | |||
195 | static void add_slack(server_t *slack) | ||
196 | { | ||
197 | struct list_head *pos; | ||
198 | server_t *queued; | ||
199 | TRACE_SERVER_SUB(slack, "adding"); | ||
200 | |||
201 | BUG_ON(head_in_list(&slack->list)); | ||
202 | |||
203 | list_for_each_prev(pos, &slack_queue) { | ||
204 | queued = list_entry(pos, server_t, list); | ||
205 | if (lt_before_eq(queued->deadline, slack->deadline)) { | ||
206 | __list_add(&slack->list, pos, pos->next); | ||
207 | return; | ||
208 | } | ||
209 | } | ||
210 | list_add(&slack->list, &slack_queue); | ||
211 | } | ||
212 | |||
213 | static void add_slack_candidate(struct task_struct *task) | ||
214 | { | ||
215 | struct list_head *pos; | ||
216 | struct task_struct *queued; | ||
217 | |||
218 | tsk_rt(task)->slack_candidate = 1; | ||
219 | INIT_LIST_HEAD(&tsk_rt(task)->slack_list); | ||
220 | |||
221 | list_for_each_prev(pos, &slack_candidates) { | ||
222 | queued = list_entry(pos, struct task_struct, | ||
223 | rt_param.slack_list); | ||
224 | if (lt_before_eq(get_deadline(queued), get_deadline(task))) { | ||
225 | TRACE_TASK_SUB(task, "adding after %d", queued->pid); | ||
226 | __list_add(&tsk_rt(task)->slack_list, | ||
227 | pos, pos->next); | ||
228 | return; | ||
229 | } | ||
230 | } | ||
231 | TRACE_TASK_SUB(task, "adding to end of list"); | ||
232 | list_add(&tsk_rt(task)->slack_list, &slack_candidates); | ||
233 | } | ||
234 | |||
235 | static struct task_struct* next_eligible_hrt(hrt_server_t*); | ||
236 | |||
237 | static void donate_slack(server_t *donator, struct task_struct *was_scheduled) | ||
238 | { | ||
239 | server_t *slack; | ||
240 | hrt_server_t *hrt_server; | ||
241 | int donate = 0; | ||
242 | |||
243 | if (donator->budget < SLACK_MIN) { | ||
244 | TRACE_SERVER_SUB(donator, "cannot donate slack"); | ||
245 | return; | ||
246 | } | ||
247 | |||
248 | if (donator->type == S_SRT && | ||
249 | donator->job_no <= task_job_no(was_scheduled)) { | ||
250 | donate = 1; | ||
251 | } else if (donator->type == S_HRT && | ||
252 | lt_before_eq(litmus_clock(), get_deadline(was_scheduled))) { | ||
253 | hrt_server = container_of(donator, hrt_server_t, server); | ||
254 | if (!next_eligible_hrt(hrt_server)) { | ||
255 | donate = 1; | ||
256 | } | ||
257 | } else if (donator-> type == S_BE && !__jobs_pending(&be_domain)) { | ||
258 | donate = 1; | ||
259 | } | ||
260 | |||
261 | if (!donate) { | ||
262 | TRACE_SERVER_SUB(donator, "doesn't want to donate slack"); | ||
263 | return; | ||
264 | } | ||
265 | |||
266 | TRACE_SERVER_SUB(donator, "donated %llu slack", TIME(donator->budget)); | ||
267 | sched_trace_action(was_scheduled, 9); | ||
268 | slack = kmalloc(sizeof(server_t), GFP_ATOMIC); | ||
269 | server_init(slack, donator->id, donator->budget, | ||
270 | donator->period, 0); | ||
271 | slack->type = S_SLACK; | ||
272 | server_release_at(slack, donator->release); | ||
273 | slack->data = donator; | ||
274 | donator->data = slack; | ||
275 | |||
276 | add_slack(slack); | ||
277 | } | ||
278 | |||
279 | static void reclaim_slack(server_t *donator) | ||
280 | { | ||
281 | TRACE_SERVER_SUB(donator, "wants to reclaim slack"); | ||
282 | } | ||
283 | |||
284 | static struct task_struct* pick_next_slack(server_t *slack, cpu_entry_t *entry) | ||
285 | { | ||
286 | struct task_struct *rv = NULL; | ||
287 | if (!slack) | ||
288 | goto out; | ||
289 | if (!list_empty(&slack_candidates)) { | ||
290 | rv = list_entry(slack_candidates.next, struct task_struct, | ||
291 | rt_param.slack_list); | ||
292 | TRACE_TASK_SUB(rv, "is next slack"); | ||
293 | } else if (entry && entry->linked && | ||
294 | entry->linked_server->type == S_SLACK) { | ||
295 | rv = entry->linked; | ||
296 | } | ||
297 | out: | ||
298 | return rv; | ||
299 | } | ||
300 | |||
301 | static void take_next_slack(struct task_struct *task) | ||
302 | { | ||
303 | if (tsk_rt(task)->slack_candidate) { | ||
304 | TRACE_TASK_SUB(task, "deleting slack"); | ||
305 | list_del(&tsk_rt(task)->slack_list); | ||
306 | tsk_rt(task)->slack_candidate = 0; | ||
307 | } else { | ||
308 | TRACE_TASK_SUB(task, "can't delete slack"); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | static void check_slack_candidate(struct task_struct *task) | ||
313 | { | ||
314 | TRACE_TASK_SUB(task, "checking"); | ||
315 | if (is_srt(task) && task_srt_server(task)->job_no >= | ||
316 | task_job_no(task) && lt_after(get_release(task), litmus_clock()) && | ||
317 | get_rt_flags(task) != RT_F_SLEEP && | ||
318 | !tsk_rt(task)->slack_candidate) | ||
319 | { | ||
320 | add_slack_candidate(task); | ||
321 | sched_trace_action(task, 8); | ||
322 | } | ||
323 | } | ||
324 | |||
123 | /* | 325 | /* |
124 | * FIFO for BE tasks. | 326 | * FIFO for BE tasks. |
125 | */ | 327 | */ |
@@ -334,37 +536,38 @@ static inline void slack_timer_cancel(hrt_server_t *hrt_server) | |||
334 | * tasks as this method cannot determine which BE server to use. | 536 | * tasks as this method cannot determine which BE server to use. |
335 | */ | 537 | */ |
336 | static noinline void link_server(cpu_entry_t *entry, | 538 | static noinline void link_server(cpu_entry_t *entry, |
337 | server_t *be_server) | 539 | server_t *next_server) |
338 | { | 540 | { |
339 | server_t *srt_server; | 541 | BUG_ON(!next_server); |
340 | 542 | ||
341 | if (is_srt(entry->linked)) { | 543 | if (next_server->type == S_SRT) { |
342 | srt_server = tsk_rt(entry->linked)->plugin_data; | ||
343 | TRACE_TASK_SUB(entry->linked, "resuming SRT server," | 544 | TRACE_TASK_SUB(entry->linked, "resuming SRT server," |
344 | "budget*: %llu, exec_time: %llu, deadline: %llu," | 545 | "budget*: %llu, exec_time: %llu, deadline: %llu," |
345 | "job_no: %d", | 546 | "job_no: %d", |
346 | srt_server->budget, get_exec_time(entry->linked), | 547 | next_server->budget, get_exec_time(entry->linked), |
347 | get_deadline(entry->linked), srt_server->job_no); | 548 | get_deadline(entry->linked), next_server->job_no); |
348 | BUG_ON(lt_after(srt_server->budget, | 549 | BUG_ON(lt_after(next_server->budget, |
349 | get_exec_cost(entry->linked))); | 550 | get_exec_cost(entry->linked))); |
350 | 551 | ||
351 | BUG_ON(srt_server->job_no < task_job_no(entry->linked)); | 552 | BUG_ON(next_server->job_no < task_job_no(entry->linked)); |
352 | BUG_ON(lt_after(get_deadline(entry->linked), | 553 | BUG_ON(lt_after(get_deadline(entry->linked), |
353 | srt_server->deadline)); | 554 | next_server->deadline)); |
354 | |||
355 | entry->linked_server = srt_server; | ||
356 | } else if (is_hrt(entry->linked)) { | 555 | } else if (is_hrt(entry->linked)) { |
357 | /* HRT servers should never, ever migrate */ | 556 | /* HRT servers should never, ever migrate */ |
358 | BUG_ON(entry->cpu != task_cpu(entry->linked)); | 557 | BUG_ON(entry->cpu != task_cpu(entry->linked)); |
359 | slack_timer_cancel(&entry->hrt_server); | 558 | slack_timer_cancel(&entry->hrt_server); |
360 | entry->linked_server = &entry->hrt_server.server; | 559 | } else if (next_server->type == S_SLACK) { |
560 | /* Should have already been removed */ | ||
561 | BUG_ON(tsk_rt(entry->linked)->slack_candidate); | ||
562 | TRACE_SERVER_SUB(next_server, "linking slack server"); | ||
563 | sched_trace_action(entry->linked, 5); | ||
564 | tsk_rt(entry->linked)->slack_server = next_server; | ||
361 | } else { /* BE */ | 565 | } else { /* BE */ |
362 | BUG_ON(!be_server); | 566 | BUG_ON(bheap_node_in_heap(next_server->hn)); |
363 | BUG_ON(bheap_node_in_heap(be_server->hn)); | 567 | sched_trace_action(entry->linked, 200 + next_server->id); |
364 | entry->linked_server = be_server; | ||
365 | sched_trace_action(entry->linked, 200 + be_server->id); | ||
366 | } | 568 | } |
367 | 569 | ||
570 | entry->linked_server = next_server; | ||
368 | server_run(entry->linked_server, entry->linked, &server_domain); | 571 | server_run(entry->linked_server, entry->linked, &server_domain); |
369 | } | 572 | } |
370 | 573 | ||
@@ -374,7 +577,7 @@ static noinline void link_server(cpu_entry_t *entry, | |||
374 | * This must be called BEFORE a task is unlinked. | 577 | * This must be called BEFORE a task is unlinked. |
375 | */ | 578 | */ |
376 | static noinline void unlink_server(cpu_entry_t *entry, | 579 | static noinline void unlink_server(cpu_entry_t *entry, |
377 | server_t *be_server) | 580 | server_t *next_server) |
378 | { | 581 | { |
379 | lt_t now; | 582 | lt_t now; |
380 | int added; | 583 | int added; |
@@ -402,8 +605,21 @@ static noinline void unlink_server(cpu_entry_t *entry, | |||
402 | 605 | ||
403 | } | 606 | } |
404 | 607 | ||
608 | if (entry->linked_server->type == S_SLACK) { | ||
609 | tsk_rt(entry->linked)->slack_server = NULL; | ||
610 | } | ||
611 | |||
612 | /* Requeue SRT servers, they will be garbage collected later */ | ||
613 | if (entry->linked_server->type == S_SLACK && | ||
614 | next_server != entry->linked_server && | ||
615 | next_server) { | ||
616 | add_slack(entry->linked_server); | ||
617 | sched_trace_action(entry->linked, 6); | ||
618 | check_slack_candidate(entry->linked); | ||
619 | } | ||
620 | |||
405 | /* Requeue eligible BE servers if they are not about to run again */ | 621 | /* Requeue eligible BE servers if they are not about to run again */ |
406 | if (is_be(entry->linked) && entry->linked_server != be_server) { | 622 | if (is_be(entry->linked) && entry->linked_server != next_server) { |
407 | if (lt_before(entry->linked_server->release, now)) { | 623 | if (lt_before(entry->linked_server->release, now)) { |
408 | TRACE_SUB("inserting %d", entry->linked_server->id); | 624 | TRACE_SUB("inserting %d", entry->linked_server->id); |
409 | bheap_insert(server_order, &be_ready_servers, | 625 | bheap_insert(server_order, &be_ready_servers, |
@@ -428,6 +644,7 @@ static noinline void unlink_server(cpu_entry_t *entry, | |||
428 | slack_timer_arm(&entry->hrt_server); | 644 | slack_timer_arm(&entry->hrt_server); |
429 | } | 645 | } |
430 | } | 646 | } |
647 | entry->linked_server = NULL; | ||
431 | } | 648 | } |
432 | 649 | ||
433 | /* Update the link of a CPU. | 650 | /* Update the link of a CPU. |
@@ -437,7 +654,7 @@ static noinline void unlink_server(cpu_entry_t *entry, | |||
437 | */ | 654 | */ |
438 | static noinline void link_task_to_cpu(cpu_entry_t *entry, | 655 | static noinline void link_task_to_cpu(cpu_entry_t *entry, |
439 | struct task_struct* linked, | 656 | struct task_struct* linked, |
440 | server_t* be_server) | 657 | server_t* next_server) |
441 | { | 658 | { |
442 | cpu_entry_t *sched; | 659 | cpu_entry_t *sched; |
443 | server_t *tmp_server; | 660 | server_t *tmp_server; |
@@ -449,7 +666,7 @@ static noinline void link_task_to_cpu(cpu_entry_t *entry, | |||
449 | 666 | ||
450 | /* Currently linked task is set to be unlinked. */ | 667 | /* Currently linked task is set to be unlinked. */ |
451 | if (entry->linked) { | 668 | if (entry->linked) { |
452 | unlink_server(entry, be_server); | 669 | unlink_server(entry, next_server); |
453 | entry->linked->rt_param.linked_on = NO_CPU; | 670 | entry->linked->rt_param.linked_on = NO_CPU; |
454 | entry->linked = NULL; | 671 | entry->linked = NULL; |
455 | } | 672 | } |
@@ -484,13 +701,12 @@ static noinline void link_task_to_cpu(cpu_entry_t *entry, | |||
484 | 701 | ||
485 | linked->rt_param.linked_on = sched->cpu; | 702 | linked->rt_param.linked_on = sched->cpu; |
486 | sched->linked = linked; | 703 | sched->linked = linked; |
487 | link_server(sched, be_server); | 704 | link_server(sched, next_server); |
488 | 705 | ||
489 | update_cpu_position(sched); | 706 | update_cpu_position(sched); |
490 | BUG_ON(!entry->linked && entry->linked_server); | ||
491 | 707 | ||
492 | linked = tmp_task; | 708 | linked = tmp_task; |
493 | be_server = tmp_server; | 709 | next_server = tmp_server; |
494 | } | 710 | } |
495 | } | 711 | } |
496 | if (linked) /* might be NULL due to swap */ | 712 | if (linked) /* might be NULL due to swap */ |
@@ -498,7 +714,7 @@ static noinline void link_task_to_cpu(cpu_entry_t *entry, | |||
498 | } | 714 | } |
499 | entry->linked = linked; | 715 | entry->linked = linked; |
500 | if (linked) | 716 | if (linked) |
501 | link_server(entry, be_server); | 717 | link_server(entry, next_server); |
502 | else | 718 | else |
503 | entry->linked_server = NULL; | 719 | entry->linked_server = NULL; |
504 | BUG_ON(!entry->linked && entry->linked_server); | 720 | BUG_ON(!entry->linked && entry->linked_server); |
@@ -627,6 +843,30 @@ static struct task_struct* next_eligible_hrt(hrt_server_t *hrt_server) | |||
627 | return task; | 843 | return task; |
628 | } | 844 | } |
629 | 845 | ||
846 | static struct task_struct* next_eligible_srt(void) | ||
847 | { | ||
848 | struct task_struct *next_srt = __peek_ready(&srt_domain); | ||
849 | server_t *srt_server; | ||
850 | |||
851 | /* Catch up srt server. This happens when the job is tardy due | ||
852 | * to overutilization of the system. | ||
853 | */ | ||
854 | if (next_srt) { | ||
855 | srt_server = tsk_rt(next_srt)->plugin_data; | ||
856 | if (srt_server->deadline < get_deadline(next_srt)) { | ||
857 | TRACE_SUB("catching up SRT to %llu", | ||
858 | get_release(next_srt)); | ||
859 | server_release_at(srt_server, get_release(next_srt)); | ||
860 | srt_server->job_no = task_job_no(next_srt); | ||
861 | } | ||
862 | } | ||
863 | |||
864 | if (next_srt && tsk_rt(next_srt)->slack_candidate) | ||
865 | take_next_slack(next_srt); | ||
866 | |||
867 | return next_srt; | ||
868 | } | ||
869 | |||
630 | /* | 870 | /* |
631 | * The highest priority BE server. | 871 | * The highest priority BE server. |
632 | */ | 872 | */ |
@@ -636,27 +876,11 @@ static inline server_t* next_be_server(void) | |||
636 | return (hn) ? hn->value : NULL; | 876 | return (hn) ? hn->value : NULL; |
637 | } | 877 | } |
638 | 878 | ||
639 | /* | 879 | static server_t* next_eligible_be_server(void) |
640 | * Either an srt task or a be server is next. The deadline of the chosen | ||
641 | * task / server is put into deadline. | ||
642 | * TODO: remove this class business. | ||
643 | */ | ||
644 | static task_class_t next_global_task(struct task_struct **task_srt, | ||
645 | server_t **server_be, | ||
646 | lt_t *deadline) | ||
647 | { | 880 | { |
648 | task_class_t rv = RT_CLASS_HARD; /* Represents invalid here */ | 881 | server_t *be_server = next_be_server(); |
649 | struct task_struct *next_srt; | ||
650 | server_t *be_server, *srt_server; | ||
651 | lt_t now = litmus_clock(); | 882 | lt_t now = litmus_clock(); |
652 | 883 | ||
653 | *task_srt = NULL; | ||
654 | *server_be = NULL; | ||
655 | *deadline = 0; | ||
656 | |||
657 | be_server = next_be_server(); | ||
658 | next_srt = __peek_ready(&srt_domain); | ||
659 | |||
660 | /* Catch up any late be servers. This happens when the servers | 884 | /* Catch up any late be servers. This happens when the servers |
661 | * could not find tasks to schedule or if the system is | 885 | * could not find tasks to schedule or if the system is |
662 | * overutilized. | 886 | * overutilized. |
@@ -670,56 +894,87 @@ static task_class_t next_global_task(struct task_struct **task_srt, | |||
670 | be_server->hn); | 894 | be_server->hn); |
671 | be_server = next_be_server(); | 895 | be_server = next_be_server(); |
672 | } | 896 | } |
897 | return be_server; | ||
898 | } | ||
673 | 899 | ||
674 | /* Catch up srt server. This happens when the job is tardy due | 900 | static inline server_t* earlier_server(server_t *first, server_t *second) |
675 | * to overutilization of the system. | 901 | { |
676 | */ | 902 | if (!first) |
677 | if (next_srt) { | 903 | return second; |
678 | srt_server = tsk_rt(next_srt)->plugin_data; | 904 | if (!second) |
679 | if (srt_server->deadline < get_deadline(next_srt)) { | 905 | return first; |
680 | TRACE_SUB("catching up SRT to %llu", | 906 | return (lt_before_eq(first->deadline, second->deadline)) ? |
681 | get_release(next_srt)); | 907 | first : second; |
682 | server_release_at(srt_server, get_release(next_srt)); | 908 | } |
683 | srt_server->job_no = task_job_no(next_srt); | ||
684 | } | ||
685 | } | ||
686 | 909 | ||
687 | TRACE_SUB("be_server: %d, next_srt: %d", | 910 | /* |
911 | * Either an srt task or a be server is next. The deadline of the chosen | ||
912 | * task / server is put into deadline. | ||
913 | * TODO: remove this class business. | ||
914 | */ | ||
915 | static lt_t next_global_task(struct task_struct **task_srt, | ||
916 | server_t **server_be, | ||
917 | server_t **server_slack) | ||
918 | { | ||
919 | struct task_struct *next_srt; | ||
920 | server_t *be_server, *slack_server, *first_server; | ||
921 | lt_t deadline = 0; | ||
922 | |||
923 | *task_srt = NULL; | ||
924 | *server_be = NULL; | ||
925 | *server_slack = NULL; | ||
926 | |||
927 | be_server = next_eligible_be_server(); | ||
928 | next_srt = next_eligible_srt(); | ||
929 | slack_server = next_eligible_slack(); | ||
930 | |||
931 | TRACE_SUB("be_server: %d, next_srt: %d, next_slack: %d", | ||
688 | (be_server) ? be_server->id : -1, | 932 | (be_server) ? be_server->id : -1, |
689 | (next_srt) ? next_srt->pid : -1); | 933 | (next_srt) ? next_srt->pid : -1, |
934 | (slack_server) ? slack_server->id : -1); | ||
690 | BUG_ON(next_srt && !is_srt(next_srt)); | 935 | BUG_ON(next_srt && !is_srt(next_srt)); |
691 | 936 | ||
692 | if (next_srt && (!be_server || | 937 | first_server = earlier_server(be_server, slack_server); |
938 | first_server = be_server; | ||
939 | |||
940 | if (next_srt && (!first_server || | ||
693 | lt_before(get_deadline(next_srt), | 941 | lt_before(get_deadline(next_srt), |
694 | be_server->deadline))) { | 942 | first_server->deadline))) { |
695 | /* SRT is next task */ | 943 | /* SRT is next task */ |
696 | *server_be = NULL; | 944 | *server_be = NULL; |
945 | *server_slack = NULL; | ||
697 | *task_srt = next_srt; | 946 | *task_srt = next_srt; |
698 | *deadline = get_deadline(next_srt); | 947 | deadline = get_deadline(next_srt); |
699 | rv = RT_CLASS_SOFT; | 948 | } else if (be_server && be_server == first_server) { |
700 | } else if (be_server) { | ||
701 | /* BE is next task */ | 949 | /* BE is next task */ |
702 | *server_be = be_server; | 950 | *server_be = be_server; |
951 | *server_slack = NULL; | ||
952 | *task_srt = NULL; | ||
953 | deadline = be_server->deadline; | ||
954 | } else if (slack_server) { | ||
955 | /* Slack is next task */ | ||
956 | *server_be = NULL; | ||
957 | *server_slack = slack_server; | ||
703 | *task_srt = NULL; | 958 | *task_srt = NULL; |
704 | *deadline = be_server->deadline; | 959 | deadline = slack_server->deadline; |
705 | rv = RT_CLASS_BEST_EFFORT; | ||
706 | } | 960 | } |
707 | 961 | ||
708 | return rv; | 962 | return deadline; |
709 | } | 963 | } |
710 | 964 | ||
711 | /* | 965 | /* |
712 | * Adds a task to the appropriate queue (ready / release) in a domain. | 966 | * Adds a task to the appropriate queue (ready / release) in a domain. |
713 | */ | 967 | */ |
714 | static noinline void requeue(struct task_struct *task, rt_domain_t *domain) | 968 | static noinline void requeue(struct task_struct *task, rt_domain_t *domain, |
969 | server_t *server) | ||
715 | { | 970 | { |
716 | int was_added; | 971 | int was_added; |
717 | BUG_ON(!is_realtime(task)); | 972 | BUG_ON(!is_realtime(task)); |
718 | BUG_ON(is_queued(task)); | ||
719 | BUG_ON(is_be(task) && domain != &be_domain); | ||
720 | BUG_ON(is_srt(task) && domain != &srt_domain); | ||
721 | 973 | ||
722 | if (is_released(task, litmus_clock())) { | 974 | if (is_queued(task)) { |
975 | if (!is_released(task, litmus_clock())) | ||
976 | check_slack_candidate(task); | ||
977 | } else if (is_released(task, litmus_clock())) { | ||
723 | TRACE_TASK_SUB(task, "requeuing on ready"); | 978 | TRACE_TASK_SUB(task, "requeuing on ready"); |
724 | __add_ready(domain, task); | 979 | __add_ready(domain, task); |
725 | } else { | 980 | } else { |
@@ -745,25 +1000,134 @@ static noinline void requeue(struct task_struct *task, rt_domain_t *domain) | |||
745 | * be tasks. For other tasks, the server can be calculated later. | 1000 | * be tasks. For other tasks, the server can be calculated later. |
746 | */ | 1001 | */ |
747 | static void preempt(cpu_entry_t *entry, struct task_struct *next, | 1002 | static void preempt(cpu_entry_t *entry, struct task_struct *next, |
748 | server_t *be_server) | 1003 | server_t *next_server) |
749 | { | 1004 | { |
750 | rt_domain_t *domain; | 1005 | rt_domain_t *domain; |
751 | 1006 | ||
752 | if (entry->linked) { | 1007 | if (entry->linked) { |
753 | domain = get_rt_domain(entry, entry->linked); | 1008 | domain = get_rt_domain(entry, entry->linked); |
754 | requeue(entry->linked, domain); | 1009 | requeue(entry->linked, domain, entry->linked_server); |
755 | } | 1010 | } |
756 | 1011 | ||
757 | link_task_to_cpu(entry, next, be_server); | 1012 | link_task_to_cpu(entry, next, next_server); |
758 | preempt_if_preemptable(entry->scheduled, entry->cpu); | 1013 | preempt_if_preemptable(entry->scheduled, entry->cpu); |
759 | } | 1014 | } |
760 | 1015 | ||
1016 | static inline struct task_struct* pick_next_be(server_t *be_server, | ||
1017 | cpu_entry_t *entry) | ||
1018 | { | ||
1019 | struct task_struct *next_be = NULL; | ||
1020 | if (!be_server) | ||
1021 | goto out; | ||
1022 | next_be = __peek_ready(&be_domain); | ||
1023 | if (!next_be && entry->linked && is_be(entry->linked)) | ||
1024 | next_be = entry->linked; | ||
1025 | out: | ||
1026 | return next_be; | ||
1027 | } | ||
1028 | |||
1029 | static cpu_entry_t* check_for_slack_preempt(struct task_struct *task, | ||
1030 | cpu_entry_t *next_entry) | ||
1031 | { | ||
1032 | cpu_entry_t *preempted = NULL; | ||
1033 | cpu_entry_t *entry = task_linked_entry(task); | ||
1034 | server_t *slack_server = task_slack_server(task); | ||
1035 | |||
1036 | BUG_ON(!is_srt(task)); | ||
1037 | |||
1038 | if (!slack_server || !slack_server->running) | ||
1039 | goto out; | ||
1040 | |||
1041 | TRACE_TASK_SUB(task, "slack preempt"); | ||
1042 | sched_trace_action(task, 10); | ||
1043 | |||
1044 | preempted = entry; | ||
1045 | |||
1046 | unlink(task); | ||
1047 | take_next_slack(task); | ||
1048 | out: | ||
1049 | return preempted; | ||
1050 | } | ||
1051 | |||
1052 | /* | ||
1053 | * Selects and links the next task for the given CPU. | ||
1054 | * TODO: this method is terrible | ||
1055 | */ | ||
1056 | static void edf_hsb_pick_next(cpu_entry_t *entry) | ||
1057 | { | ||
1058 | lt_t deadline; | ||
1059 | struct task_struct *next_hrt, *next_srt, *next_be, *next_slack; | ||
1060 | server_t *be_server, *slack_server; | ||
1061 | cpu_entry_t *preempted; | ||
1062 | |||
1063 | BUG_ON(entry->linked); | ||
1064 | |||
1065 | next_hrt = next_eligible_hrt(&entry->hrt_server); | ||
1066 | |||
1067 | if (next_hrt) { | ||
1068 | /* HRT is next task */ | ||
1069 | link_task_to_cpu(entry, next_hrt, &entry->hrt_server.server); | ||
1070 | remove(&entry->hrt_server.hrt_domain, next_hrt); | ||
1071 | } else { | ||
1072 | deadline = next_global_task(&next_srt, | ||
1073 | &be_server, | ||
1074 | &slack_server); | ||
1075 | |||
1076 | if (next_srt) { | ||
1077 | remove(&srt_domain, next_srt); | ||
1078 | |||
1079 | preempted = check_for_slack_preempt(next_srt, entry); | ||
1080 | if (preempted) { | ||
1081 | edf_hsb_pick_next(preempted); | ||
1082 | preempt_if_preemptable(preempted->scheduled, | ||
1083 | preempted->cpu); | ||
1084 | } | ||
1085 | |||
1086 | link_task_to_cpu(entry, next_srt, | ||
1087 | task_srt_server(next_srt)); | ||
1088 | } else if (be_server) { | ||
1089 | next_be = __take_ready(&be_domain); | ||
1090 | |||
1091 | if (next_be) { | ||
1092 | TRACE_SUB("deleting be server %d", | ||
1093 | be_server->id); | ||
1094 | bheap_delete(server_order, &be_ready_servers, | ||
1095 | be_server->hn); | ||
1096 | link_task_to_cpu(entry, next_be, be_server); | ||
1097 | } | ||
1098 | } else if (slack_server) { | ||
1099 | next_slack = pick_next_slack(slack_server, NULL); | ||
1100 | |||
1101 | if (next_slack) { | ||
1102 | take_next_slack(next_slack); | ||
1103 | list_del(&slack_server->list); | ||
1104 | TRACE_TASK_SUB(next_slack, "taking"); | ||
1105 | link_task_to_cpu(entry, next_slack, slack_server); | ||
1106 | } | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | /* Try SRT again */ | ||
1111 | if (!entry->linked) { | ||
1112 | next_srt = __take_ready(&srt_domain); | ||
1113 | if (!next_srt) | ||
1114 | return; | ||
1115 | preempted = check_for_slack_preempt(next_srt, entry); | ||
1116 | if (preempted) { | ||
1117 | edf_hsb_pick_next(preempted); | ||
1118 | preempt_if_preemptable(preempted->scheduled, | ||
1119 | preempted->cpu); | ||
1120 | } | ||
1121 | |||
1122 | link_task_to_cpu(entry, next_srt, task_srt_server(next_srt)); | ||
1123 | } | ||
1124 | } | ||
1125 | |||
761 | static void check_for_global_preempt(void) | 1126 | static void check_for_global_preempt(void) |
762 | { | 1127 | { |
763 | task_class_t class; | ||
764 | cpu_entry_t *entry; | 1128 | cpu_entry_t *entry; |
765 | server_t *be_server = NULL; | 1129 | server_t *be_server = NULL, *slack_server = NULL, *next_server; |
766 | struct task_struct *next_srt, *next_be; | 1130 | struct task_struct *next_srt, *next_be, *next_slack; |
767 | struct task_struct *next_task = (struct task_struct*)1; /* Not null */ | 1131 | struct task_struct *next_task = (struct task_struct*)1; /* Not null */ |
768 | lt_t deadline; | 1132 | lt_t deadline; |
769 | 1133 | ||
@@ -775,21 +1139,27 @@ static void check_for_global_preempt(void) | |||
775 | BUG_ON(entry->linked && is_hrt(entry->linked)); | 1139 | BUG_ON(entry->linked && is_hrt(entry->linked)); |
776 | 1140 | ||
777 | /* Get the potential challengers */ | 1141 | /* Get the potential challengers */ |
778 | class = next_global_task(&next_srt, | 1142 | deadline = next_global_task(&next_srt, |
779 | &be_server, | 1143 | &be_server, |
780 | &deadline); | 1144 | &slack_server); |
781 | next_be = __peek_ready(&be_domain); | 1145 | next_be = pick_next_be(be_server, entry); |
1146 | next_slack = pick_next_slack(slack_server, entry); | ||
782 | 1147 | ||
783 | /* If there is no existing BE, then the server must have | 1148 | /* If there is no existing BE, then the server must have |
784 | * a new BE task to schedule. If it doesn't, try SRT. | 1149 | * a new BE task to schedule. If it doesn't, others. |
785 | */ | 1150 | */ |
786 | if (be_server && !next_be && | 1151 | if (be_server && !next_be) { |
787 | (!entry->linked || !is_be(entry->linked))) { | ||
788 | TRACE_SUB("2"); | 1152 | TRACE_SUB("2"); |
789 | be_server = NULL; | 1153 | be_server = NULL; |
790 | next_srt = __peek_ready(&srt_domain); | 1154 | next_srt = next_eligible_srt(); |
1155 | deadline = (next_srt) ?get_deadline(next_srt) : 0; | ||
1156 | } | ||
1157 | |||
1158 | if (slack_server && !next_slack) { | ||
1159 | TRACE_SUB("3"); | ||
1160 | slack_server = NULL; | ||
1161 | next_srt = next_eligible_srt(); | ||
791 | deadline = (next_srt) ?get_deadline(next_srt) : 0; | 1162 | deadline = (next_srt) ?get_deadline(next_srt) : 0; |
792 | class = RT_CLASS_SOFT; | ||
793 | } | 1163 | } |
794 | 1164 | ||
795 | TRACE_SUB("4"); | 1165 | TRACE_SUB("4"); |
@@ -815,8 +1185,7 @@ static void check_for_global_preempt(void) | |||
815 | lt_before(deadline, entry->linked_server->deadline)){ | 1185 | lt_before(deadline, entry->linked_server->deadline)){ |
816 | TRACE_SUB("8"); | 1186 | TRACE_SUB("8"); |
817 | /* Swap two BE servers here */ | 1187 | /* Swap two BE servers here */ |
818 | if ((class & get_class(entry->linked)) == | 1188 | if (be_server && entry->linked_server->type == S_BE) { |
819 | RT_CLASS_BEST_EFFORT) { | ||
820 | TRACE_SUB("9"); | 1189 | TRACE_SUB("9"); |
821 | bheap_delete(server_order, | 1190 | bheap_delete(server_order, |
822 | &be_ready_servers, | 1191 | &be_ready_servers, |
@@ -827,6 +1196,16 @@ static void check_for_global_preempt(void) | |||
827 | next_task = entry->linked; | 1196 | next_task = entry->linked; |
828 | goto loop_end; | 1197 | goto loop_end; |
829 | } | 1198 | } |
1199 | /* Swap two slack servers here */ | ||
1200 | if (slack_server && entry->linked_server->type == S_SLACK) { | ||
1201 | TRACE_SUB("9.5"); | ||
1202 | list_del(&slack_server->list); | ||
1203 | unlink_server(entry, slack_server); | ||
1204 | link_server(entry, slack_server); | ||
1205 | update_cpu_position(entry); | ||
1206 | next_task = entry->linked; | ||
1207 | goto loop_end; | ||
1208 | } | ||
830 | TRACE_SUB("10"); | 1209 | TRACE_SUB("10"); |
831 | goto loop_end_preempt; | 1210 | goto loop_end_preempt; |
832 | } | 1211 | } |
@@ -835,9 +1214,11 @@ static void check_for_global_preempt(void) | |||
835 | 1214 | ||
836 | loop_end_preempt: | 1215 | loop_end_preempt: |
837 | TRACE_SUB("13"); | 1216 | TRACE_SUB("13"); |
838 | if (class == RT_CLASS_SOFT) { | 1217 | if (next_srt) { |
839 | next_task = next_srt; | 1218 | next_task = next_srt; |
840 | } else { | 1219 | next_server = task_srt_server(next_task); |
1220 | check_for_slack_preempt(next_srt, entry); | ||
1221 | } else if (next_be) { | ||
841 | next_task = next_be; | 1222 | next_task = next_be; |
842 | if (bheap_node_in_heap(be_server->hn)) { | 1223 | if (bheap_node_in_heap(be_server->hn)) { |
843 | TRACE_SUB("deleting be server %d", | 1224 | TRACE_SUB("deleting be server %d", |
@@ -845,11 +1226,20 @@ static void check_for_global_preempt(void) | |||
845 | bheap_delete(server_order, &be_ready_servers, | 1226 | bheap_delete(server_order, &be_ready_servers, |
846 | be_server->hn); | 1227 | be_server->hn); |
847 | } | 1228 | } |
1229 | next_server = be_server; | ||
1230 | } else { /* Slack */ | ||
1231 | next_task = next_slack; | ||
1232 | next_server = slack_server; | ||
1233 | list_del(&slack_server->list); | ||
848 | } | 1234 | } |
849 | BUG_ON(!next_task); | 1235 | BUG_ON(!next_task); |
850 | TRACE_TASK_SUB(next_task, "preempting on P%d", entry->cpu); | 1236 | TRACE_TASK_SUB(next_task, "preempting on P%d", entry->cpu); |
851 | remove(get_rt_domain(entry, next_task), next_task); | 1237 | |
852 | preempt(entry, next_task, be_server); | 1238 | if (next_server != slack_server && is_queued(next_task)) |
1239 | remove(get_rt_domain(entry, next_task), next_task); | ||
1240 | else if (next_slack) | ||
1241 | take_next_slack(next_slack); | ||
1242 | preempt(entry, next_task, next_server); | ||
853 | 1243 | ||
854 | loop_end: | 1244 | loop_end: |
855 | TRACE_SUB("14"); | 1245 | TRACE_SUB("14"); |
@@ -868,15 +1258,18 @@ static void check_for_hrt_preempt(cpu_entry_t *entry) | |||
868 | 1258 | ||
869 | TRACE_SUB("checking for HRT preempt on P%d", entry->cpu); | 1259 | TRACE_SUB("checking for HRT preempt on P%d", entry->cpu); |
870 | 1260 | ||
1261 | if (next_hrt) | ||
1262 | reclaim_slack(&server->server); | ||
1263 | |||
871 | if (next_hrt && | 1264 | if (next_hrt && |
872 | (!entry->linked || !is_hrt(entry->linked) || | 1265 | (!entry->linked || !is_hrt(entry->linked) || |
873 | edf_preemption_needed(&server->hrt_domain, entry->linked))) { | 1266 | edf_preemption_needed(&server->hrt_domain, entry->linked))) { |
874 | 1267 | ||
875 | TRACE_TASK_SUB(next_hrt, "preempting on CPU %d", entry->cpu); | 1268 | TRACE_TASK_SUB(next_hrt, "preempting on CPU %d", entry->cpu); |
876 | remove(&server->hrt_domain, next_hrt); | 1269 | remove(&server->hrt_domain, next_hrt); |
877 | preempt(entry, next_hrt, NULL); | 1270 | preempt(entry, next_hrt, &server->server); |
878 | 1271 | ||
879 | /* We might have just kicked off an SRT. Check to see if it | 1272 | /* We might have just kicked off something. Check to see if it |
880 | * preempts anything. | 1273 | * preempts anything. |
881 | */ | 1274 | */ |
882 | if (curr && !is_hrt(curr)) | 1275 | if (curr && !is_hrt(curr)) |
@@ -900,14 +1293,14 @@ static void job_arrival(struct task_struct *task, cpu_entry_t *entry) | |||
900 | TRACE_TASK_SUB(task, "Arriving on P%d", entry->cpu); | 1293 | TRACE_TASK_SUB(task, "Arriving on P%d", entry->cpu); |
901 | 1294 | ||
902 | if (is_hrt(task)) { | 1295 | if (is_hrt(task)) { |
903 | requeue(task, &entry->hrt_server.hrt_domain); | 1296 | requeue(task, &entry->hrt_server.hrt_domain, NULL); |
904 | check_for_hrt_preempt(entry); | 1297 | check_for_hrt_preempt(entry); |
905 | } else if (is_srt(task)) { | 1298 | } else if (is_srt(task)) { |
906 | requeue(task, &srt_domain); | 1299 | requeue(task, &srt_domain, NULL); |
907 | check_for_global_preempt(); | 1300 | check_for_global_preempt(); |
908 | } else /* BE */ { | 1301 | } else /* BE */ { |
909 | was_empty = !__jobs_pending(&be_domain); | 1302 | was_empty = !__jobs_pending(&be_domain); |
910 | requeue(task, &be_domain); | 1303 | requeue(task, &be_domain, NULL); |
911 | 1304 | ||
912 | /* Only way this could cause a preemption is if | 1305 | /* Only way this could cause a preemption is if |
913 | * an eligible BE server could not queue up a task. | 1306 | * an eligible BE server could not queue up a task. |
@@ -917,51 +1310,6 @@ static void job_arrival(struct task_struct *task, cpu_entry_t *entry) | |||
917 | } | 1310 | } |
918 | } | 1311 | } |
919 | 1312 | ||
920 | /* | ||
921 | * Selects and links the next task for the given CPU. | ||
922 | */ | ||
923 | static void edf_hsb_pick_next(cpu_entry_t *entry) | ||
924 | { | ||
925 | task_class_t class; | ||
926 | lt_t deadline; | ||
927 | struct task_struct *next_hrt, *next_srt, *next_be; | ||
928 | server_t *be_server; | ||
929 | |||
930 | BUG_ON(entry->linked); | ||
931 | |||
932 | next_hrt = next_eligible_hrt(&entry->hrt_server); | ||
933 | |||
934 | if (next_hrt) { | ||
935 | /* HRT is next task */ | ||
936 | link_task_to_cpu(entry, next_hrt, NULL); | ||
937 | remove(&entry->hrt_server.hrt_domain, next_hrt); | ||
938 | } else { | ||
939 | class = next_global_task(&next_srt, | ||
940 | &be_server, | ||
941 | &deadline); | ||
942 | if (next_srt) { | ||
943 | remove(&srt_domain, next_srt); | ||
944 | link_task_to_cpu(entry, next_srt, NULL); | ||
945 | } else if (be_server) { | ||
946 | next_be = __take_ready(&be_domain); | ||
947 | |||
948 | if (next_be) { | ||
949 | TRACE_SUB("deleting be server %d", | ||
950 | be_server->id); | ||
951 | bheap_delete(server_order, &be_ready_servers, | ||
952 | be_server->hn); | ||
953 | link_task_to_cpu(entry, next_be, be_server); | ||
954 | } else { | ||
955 | /* Nothing to schedule! Try SRT */ | ||
956 | next_srt = __take_ready(&srt_domain); | ||
957 | if (!next_srt) | ||
958 | return; | ||
959 | link_task_to_cpu(entry, next_srt, NULL); | ||
960 | } | ||
961 | } | ||
962 | } | ||
963 | } | ||
964 | |||
965 | /****************************************************************************** | 1313 | /****************************************************************************** |
966 | * Timer methods | 1314 | * Timer methods |
967 | ******************************************************************************/ | 1315 | ******************************************************************************/ |
@@ -1069,26 +1417,37 @@ static enum hrtimer_restart slack_timer_fire(struct hrtimer *timer) | |||
1069 | 1417 | ||
1070 | static void job_completion(cpu_entry_t *entry, struct task_struct* task) | 1418 | static void job_completion(cpu_entry_t *entry, struct task_struct* task) |
1071 | { | 1419 | { |
1072 | server_t *srt_server; | 1420 | server_t *server = entry->linked_server; |
1073 | set_rt_flags(task, RT_F_SLEEP); | 1421 | set_rt_flags(task, RT_F_SLEEP); |
1074 | 1422 | ||
1075 | TRACE_TASK_SUB(task, "completed"); | 1423 | TRACE_TASK_SUB(task, "completed"); |
1076 | 1424 | ||
1077 | unlink(task); | 1425 | unlink(task); |
1078 | 1426 | ||
1079 | if (is_srt(task)) { | 1427 | donate_slack(server, task); |
1080 | srt_server = tsk_rt(task)->plugin_data; | 1428 | |
1429 | if (server->type == S_SLACK && is_srt(task)) { | ||
1430 | TRACE_TASK_SUB(task, "slack server catching up"); | ||
1431 | tsk_rt(task)->job_params.job_no++; | ||
1432 | add_slack(server); | ||
1433 | check_slack_candidate(task); | ||
1434 | sched_trace_task_completion(task, 1); | ||
1435 | return; | ||
1436 | } | ||
1437 | |||
1438 | BUG_ON(is_queued(task)); | ||
1081 | 1439 | ||
1440 | if (server->type == S_SRT) { | ||
1082 | /* If the task is behind the server it must release immediately, | 1441 | /* If the task is behind the server it must release immediately, |
1083 | * leaving its release time and deadline unchanged. | 1442 | * leaving its release time and deadline unchanged. |
1084 | */ | 1443 | */ |
1085 | if (srt_server->job_no > tsk_rt(task)->job_params.job_no) { | 1444 | if (server->job_no > tsk_rt(task)->job_params.job_no) { |
1086 | TRACE_TASK_SUB(task, "catching up"); | 1445 | TRACE_TASK_SUB(task, "catching up"); |
1087 | tsk_rt(task)->job_params.job_no++; | 1446 | tsk_rt(task)->job_params.job_no++; |
1088 | } else { | 1447 | } else { |
1089 | /* Otherwise release them both */ | 1448 | /* Otherwise release them both */ |
1090 | prepare_for_next_period(task); | 1449 | prepare_for_next_period(task); |
1091 | server_release(srt_server); | 1450 | server_release(server); |
1092 | } | 1451 | } |
1093 | } else { | 1452 | } else { |
1094 | prepare_for_next_period(task); | 1453 | prepare_for_next_period(task); |
@@ -1115,9 +1474,9 @@ static void server_completed(server_t *server, struct task_struct *task) | |||
1115 | TRACE_TASK_TIMER(task, "server %d completed, task exec: %llu", | 1474 | TRACE_TASK_TIMER(task, "server %d completed, task exec: %llu", |
1116 | server->id, get_exec_time(task)); | 1475 | server->id, get_exec_time(task)); |
1117 | BUG_ON(entry->linked != task); | 1476 | BUG_ON(entry->linked != task); |
1118 | sched_trace_action(entry->linked, 1); | 1477 | //sched_trace_action(entry->linked, 1); |
1119 | 1478 | ||
1120 | if (is_srt(task)) { | 1479 | if (server->type == S_SRT) { |
1121 | TRACE_TASK_SUB(task, "must wait on server"); | 1480 | TRACE_TASK_SUB(task, "must wait on server"); |
1122 | 1481 | ||
1123 | /* The job must now take the priority and release time | 1482 | /* The job must now take the priority and release time |
@@ -1131,6 +1490,8 @@ static void server_completed(server_t *server, struct task_struct *task) | |||
1131 | tsk_rt(task)->job_params.release = server->deadline; | 1490 | tsk_rt(task)->job_params.release = server->deadline; |
1132 | tsk_rt(task)->job_params.deadline = server->deadline + | 1491 | tsk_rt(task)->job_params.deadline = server->deadline + |
1133 | get_rt_period(task); | 1492 | get_rt_period(task); |
1493 | |||
1494 | check_slack_candidate(task); | ||
1134 | } | 1495 | } |
1135 | 1496 | ||
1136 | /* Someone else may have brought this server forward. | 1497 | /* Someone else may have brought this server forward. |
@@ -1143,14 +1504,15 @@ static void server_completed(server_t *server, struct task_struct *task) | |||
1143 | hrt_server = container_of(server, hrt_server_t, server); | 1504 | hrt_server = container_of(server, hrt_server_t, server); |
1144 | TRACE_SUB("P%d no longer ready", entry->cpu); | 1505 | TRACE_SUB("P%d no longer ready", entry->cpu); |
1145 | hrt_server->ready = 0; | 1506 | hrt_server->ready = 0; |
1146 | } | 1507 | } |
1147 | 1508 | ||
1148 | unlink(task); | 1509 | unlink(task); |
1149 | requeue(task, get_rt_domain(entry, task)); | 1510 | requeue(task, get_rt_domain(entry, task), server); |
1150 | 1511 | ||
1151 | /* Need to pick the next task to run */ | 1512 | /* Need to pick the next task to run */ |
1152 | edf_hsb_pick_next(entry); | 1513 | check_for_global_preempt(); |
1153 | preempt_if_preemptable(entry->scheduled, entry->cpu); | 1514 | if (!entry->linked) |
1515 | preempt_if_preemptable(entry->scheduled, entry->cpu); | ||
1154 | } | 1516 | } |
1155 | 1517 | ||
1156 | static void hrt_server_released(server_t *server) | 1518 | static void hrt_server_released(server_t *server) |
@@ -1169,14 +1531,16 @@ static void hrt_server_released(server_t *server) | |||
1169 | if (entry->linked && is_hrt(entry->linked) && | 1531 | if (entry->linked && is_hrt(entry->linked) && |
1170 | !is_eligible(entry->linked, hrt_server)) { | 1532 | !is_eligible(entry->linked, hrt_server)) { |
1171 | 1533 | ||
1172 | requeue(entry->linked, &hrt_server->hrt_domain); | 1534 | requeue(entry->linked, &hrt_server->hrt_domain, |
1535 | entry->linked_server); | ||
1173 | unlink(entry->linked); | 1536 | unlink(entry->linked); |
1174 | 1537 | ||
1175 | server_release(server); | 1538 | server_release(server); |
1176 | edf_hsb_pick_next(entry); | 1539 | edf_hsb_pick_next(entry); |
1177 | preempt_if_preemptable(entry->scheduled, entry->cpu); | 1540 | preempt_if_preemptable(entry->scheduled, entry->cpu); |
1178 | } else { | 1541 | } else { |
1179 | /* Otherwise check to see if a different task should * be running. | 1542 | /* Otherwise check to see if a different task should |
1543 | * be running. | ||
1180 | */ | 1544 | */ |
1181 | check_for_hrt_preempt(entry); | 1545 | check_for_hrt_preempt(entry); |
1182 | 1546 | ||
@@ -1204,7 +1568,7 @@ static void servers_released(struct list_head *servers) | |||
1204 | list_for_each(pos, servers) { | 1568 | list_for_each(pos, servers) { |
1205 | server = list_entry(pos, server_t, release_list); | 1569 | server = list_entry(pos, server_t, release_list); |
1206 | 1570 | ||
1207 | if (server->type == RT_CLASS_BEST_EFFORT) { | 1571 | if (server->type == S_BE) { |
1208 | was_be = 1; | 1572 | was_be = 1; |
1209 | BUG_ON(bheap_node_in_heap(server->hn)); | 1573 | BUG_ON(bheap_node_in_heap(server->hn)); |
1210 | TRACE_SUB("inserting be server %d", server->id); | 1574 | TRACE_SUB("inserting be server %d", server->id); |
@@ -1249,7 +1613,7 @@ static int admit_be_server(unsigned long long wcet, | |||
1249 | be_server = kmalloc(sizeof(server_t), GFP_ATOMIC); | 1613 | be_server = kmalloc(sizeof(server_t), GFP_ATOMIC); |
1250 | server_init(be_server, BE_SERVER_BASE + ++curr_be, | 1614 | server_init(be_server, BE_SERVER_BASE + ++curr_be, |
1251 | wcet, period, 1); | 1615 | wcet, period, 1); |
1252 | be_server->type = RT_CLASS_BEST_EFFORT; | 1616 | be_server->type = S_BE; |
1253 | 1617 | ||
1254 | TRACE("created BE server %d (%llu, %llu)\n", be_server->id, | 1618 | TRACE("created BE server %d (%llu, %llu)\n", be_server->id, |
1255 | wcet, period); | 1619 | wcet, period); |
@@ -1314,7 +1678,7 @@ static int admit_hrt_server(unsigned long long wcet, | |||
1314 | hrt_server->no_slack = 0; | 1678 | hrt_server->no_slack = 0; |
1315 | 1679 | ||
1316 | server_init(&hrt_server->server, cpu, wcet, period, 1); | 1680 | server_init(&hrt_server->server, cpu, wcet, period, 1); |
1317 | hrt_server->server.type = RT_CLASS_HARD; | 1681 | hrt_server->server.type = S_HRT; |
1318 | 1682 | ||
1319 | edf_domain_init(&hrt_server->hrt_domain, NULL, | 1683 | edf_domain_init(&hrt_server->hrt_domain, NULL, |
1320 | release_hrt_jobs); | 1684 | release_hrt_jobs); |
@@ -1603,8 +1967,6 @@ static struct task_struct* edf_hsb_schedule(struct task_struct *prev) | |||
1603 | entry->scheduled = entry->linked; | 1967 | entry->scheduled = entry->linked; |
1604 | sched_state_task_picked(); | 1968 | sched_state_task_picked(); |
1605 | 1969 | ||
1606 | BUG_ON(entry->scheduled && is_queued(entry->scheduled)); | ||
1607 | |||
1608 | if (entry->scheduled) | 1970 | if (entry->scheduled) |
1609 | TRACE_TASK(entry->scheduled, "scheduled at %llu\n", | 1971 | TRACE_TASK(entry->scheduled, "scheduled at %llu\n", |
1610 | TIME(litmus_clock())); | 1972 | TIME(litmus_clock())); |
@@ -1637,7 +1999,8 @@ static void edf_hsb_task_new(struct task_struct *task, int on_rq, int running) | |||
1637 | srt_server = kmalloc(sizeof(server_t), GFP_ATOMIC); | 1999 | srt_server = kmalloc(sizeof(server_t), GFP_ATOMIC); |
1638 | server_init(srt_server, task->pid, get_exec_cost(task), | 2000 | server_init(srt_server, task->pid, get_exec_cost(task), |
1639 | get_rt_period(task), 0); | 2001 | get_rt_period(task), 0); |
1640 | srt_server->type = RT_CLASS_SOFT; | 2002 | srt_server->type = S_SRT; |
2003 | srt_server->data = task; | ||
1641 | srt_server->job_no = tsk_rt(task)->job_params.job_no; | 2004 | srt_server->job_no = tsk_rt(task)->job_params.job_no; |
1642 | server_release_at(srt_server, get_release(task)); | 2005 | server_release_at(srt_server, get_release(task)); |
1643 | } | 2006 | } |
@@ -1758,6 +2121,8 @@ static int __init init_edf_hsb(void) | |||
1758 | bheap_init(&cpu_heap); | 2121 | bheap_init(&cpu_heap); |
1759 | bheap_init(&be_ready_servers); | 2122 | bheap_init(&be_ready_servers); |
1760 | INIT_LIST_HEAD(&be_servers); | 2123 | INIT_LIST_HEAD(&be_servers); |
2124 | INIT_LIST_HEAD(&slack_queue); | ||
2125 | INIT_LIST_HEAD(&slack_candidates); | ||
1761 | 2126 | ||
1762 | for_each_online_cpu(cpu) { | 2127 | for_each_online_cpu(cpu) { |
1763 | entry = &per_cpu(cpu_entries, cpu); | 2128 | entry = &per_cpu(cpu_entries, cpu); |