diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-12-06 20:37:20 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-12-06 20:37:20 -0500 |
commit | 983773f990053cb0ced72afb4b69594e5d32c779 (patch) | |
tree | 27767f1719926a3973a2d9effa943ea1437f9a1c | |
parent | 964297dd588ee6feab1aedecb2611bece2681973 (diff) |
AUX_FUTURE and revised inh-based aux tie break
-rwxr-xr-x[-rw-r--r--] | include/litmus/aux_tasks.h | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | include/litmus/litmus.h | 1 | ||||
-rwxr-xr-x[-rw-r--r--] | include/litmus/rt_param.h | 7 | ||||
-rw-r--r-- | kernel/fork.c | 6 | ||||
-rwxr-xr-x | litmus/aux_tasks.c | 198 | ||||
-rwxr-xr-x | litmus/edf_common.c | 78 | ||||
-rwxr-xr-x[-rw-r--r--] | litmus/litmus.c | 8 |
7 files changed, 192 insertions, 108 deletions
diff --git a/include/litmus/aux_tasks.h b/include/litmus/aux_tasks.h index 3bb6b26fef09..87745c1c0df0 100644..100755 --- a/include/litmus/aux_tasks.h +++ b/include/litmus/aux_tasks.h | |||
@@ -6,6 +6,8 @@ struct task_struct; | |||
6 | /* admit an aux task with default parameters */ | 6 | /* admit an aux task with default parameters */ |
7 | //int admit_aux_task(struct task_struct *t); | 7 | //int admit_aux_task(struct task_struct *t); |
8 | 8 | ||
9 | int make_aux_task_if_required(struct task_struct *t); | ||
10 | |||
9 | /* call on an aux task when it exits real-time */ | 11 | /* call on an aux task when it exits real-time */ |
10 | int exit_aux_task(struct task_struct *t); | 12 | int exit_aux_task(struct task_struct *t); |
11 | 13 | ||
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index db2987a24686..711b88e2b3d1 100644..100755 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h | |||
@@ -32,6 +32,7 @@ struct task_struct* __waitqueue_remove_first(wait_queue_head_t *wq); | |||
32 | #define NO_CPU 0xffffffff | 32 | #define NO_CPU 0xffffffff |
33 | 33 | ||
34 | void litmus_fork(struct task_struct *tsk); | 34 | void litmus_fork(struct task_struct *tsk); |
35 | void litmus_post_fork_thread(struct task_struct *tsk); | ||
35 | void litmus_exec(void); | 36 | void litmus_exec(void); |
36 | /* clean up real-time state of a task */ | 37 | /* clean up real-time state of a task */ |
37 | void exit_litmus(struct task_struct *dead_tsk); | 38 | void exit_litmus(struct task_struct *dead_tsk); |
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index cb7c3ac64339..aca78a835529 100644..100755 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -41,6 +41,12 @@ typedef enum { | |||
41 | PRECISE_SIGNALS, /* budget signals are triggered with hrtimers */ | 41 | PRECISE_SIGNALS, /* budget signals are triggered with hrtimers */ |
42 | } budget_signal_policy_t; | 42 | } budget_signal_policy_t; |
43 | 43 | ||
44 | typedef enum { | ||
45 | AUX_ENABLE = 0x1, | ||
46 | AUX_CURRENT = (AUX_ENABLE<<1), | ||
47 | AUX_FUTURE = (AUX_CURRENT<<2) | ||
48 | } aux_flags_t; | ||
49 | |||
44 | /* We use the common priority interpretation "lower index == higher priority", | 50 | /* We use the common priority interpretation "lower index == higher priority", |
45 | * which is commonly used in fixed-priority schedulability analysis papers. | 51 | * which is commonly used in fixed-priority schedulability analysis papers. |
46 | * So, a numerically lower priority value implies higher scheduling priority, | 52 | * So, a numerically lower priority value implies higher scheduling priority, |
@@ -370,6 +376,7 @@ struct aux_data | |||
370 | struct list_head aux_tasks; | 376 | struct list_head aux_tasks; |
371 | struct binheap aux_task_owners; | 377 | struct binheap aux_task_owners; |
372 | unsigned int initialized:1; | 378 | unsigned int initialized:1; |
379 | unsigned int aux_future:1; | ||
373 | }; | 380 | }; |
374 | #endif | 381 | #endif |
375 | 382 | ||
diff --git a/kernel/fork.c b/kernel/fork.c index 25c6111fe3a6..7491c4f5e78c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1370,8 +1370,12 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1370 | write_unlock_irq(&tasklist_lock); | 1370 | write_unlock_irq(&tasklist_lock); |
1371 | proc_fork_connector(p); | 1371 | proc_fork_connector(p); |
1372 | cgroup_post_fork(p); | 1372 | cgroup_post_fork(p); |
1373 | if (clone_flags & CLONE_THREAD) | 1373 | if (clone_flags & CLONE_THREAD) { |
1374 | threadgroup_fork_read_unlock(current); | 1374 | threadgroup_fork_read_unlock(current); |
1375 | #ifdef CONFIG_REALTIME_AUX_TASKS | ||
1376 | litmus_post_fork_thread(p); | ||
1377 | #endif | ||
1378 | } | ||
1375 | perf_event_fork(p); | 1379 | perf_event_fork(p); |
1376 | return p; | 1380 | return p; |
1377 | 1381 | ||
diff --git a/litmus/aux_tasks.c b/litmus/aux_tasks.c index bd7bcbed58fe..e5f3c82d32e9 100755 --- a/litmus/aux_tasks.c +++ b/litmus/aux_tasks.c | |||
@@ -25,7 +25,7 @@ static int admit_aux_task(struct task_struct *t) | |||
25 | struct rt_task tp = { | 25 | struct rt_task tp = { |
26 | .period = 1000000, /* 1ms */ | 26 | .period = 1000000, /* 1ms */ |
27 | .relative_deadline = 1000000, | 27 | .relative_deadline = 1000000, |
28 | .exec_cost = 1000000, /* allow full utilization */ | 28 | .exec_cost = 1000000, /* allow full utilization with buget tracking */ |
29 | .phase = 0, | 29 | .phase = 0, |
30 | .cpu = task_cpu(leader), /* take CPU of group leader */ | 30 | .cpu = task_cpu(leader), /* take CPU of group leader */ |
31 | .budget_policy = QUANTUM_ENFORCEMENT, | 31 | .budget_policy = QUANTUM_ENFORCEMENT, |
@@ -44,17 +44,15 @@ static int admit_aux_task(struct task_struct *t) | |||
44 | int exit_aux_task(struct task_struct *t) | 44 | int exit_aux_task(struct task_struct *t) |
45 | { | 45 | { |
46 | int retval = 0; | 46 | int retval = 0; |
47 | struct task_struct *leader = t->group_leader; | ||
48 | 47 | ||
49 | BUG_ON(!tsk_rt(t)->is_aux_task); | 48 | BUG_ON(!tsk_rt(t)->is_aux_task); |
50 | 49 | ||
51 | TRACE_CUR("Aux task %s/%d is exiting from %s/%d.\n", t->comm, t->pid, leader->comm, leader->pid); | 50 | TRACE_CUR("Aux task %s/%d is exiting from %s/%d.\n", t->comm, t->pid, t->group_leader->comm, t->group_leader->pid); |
52 | 51 | ||
52 | tsk_rt(t)->is_aux_task = 0; | ||
53 | |||
53 | #ifdef CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE | 54 | #ifdef CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE |
54 | list_del(&tsk_rt(t)->aux_task_node); | 55 | list_del(&tsk_rt(t)->aux_task_node); |
55 | |||
56 | tsk_rt(t)->is_aux_task = 0; | ||
57 | |||
58 | if (tsk_rt(t)->inh_task) { | 56 | if (tsk_rt(t)->inh_task) { |
59 | litmus->__decrease_prio(t, NULL); | 57 | litmus->__decrease_prio(t, NULL); |
60 | } | 58 | } |
@@ -80,10 +78,14 @@ static int aux_tasks_increase_priority(struct task_struct *leader, struct task_s | |||
80 | if (!is_realtime(aux)) { | 78 | if (!is_realtime(aux)) { |
81 | TRACE_CUR("skipping non-real-time aux task %s/%d\n", aux->comm, aux->pid); | 79 | TRACE_CUR("skipping non-real-time aux task %s/%d\n", aux->comm, aux->pid); |
82 | } | 80 | } |
83 | 81 | else if(tsk_rt(aux)->inh_task == hp) { | |
84 | // aux tasks don't touch rt locks, so no nested call needed. | 82 | TRACE_CUR("skipping real-time aux task %s/%d that already inherits from %s/%d\n", aux->comm, aux->pid, hp->comm, hp->pid); |
85 | TRACE_CUR("increasing %s/%d.\n", aux->comm, aux->pid); | 83 | } |
86 | retval = litmus->__increase_prio(aux, hp); | 84 | else { |
85 | // aux tasks don't touch rt locks, so no nested call needed. | ||
86 | TRACE_CUR("increasing %s/%d.\n", aux->comm, aux->pid); | ||
87 | retval = litmus->__increase_prio(aux, hp); | ||
88 | } | ||
87 | } | 89 | } |
88 | #endif | 90 | #endif |
89 | 91 | ||
@@ -208,6 +210,54 @@ out: | |||
208 | return retval; | 210 | return retval; |
209 | } | 211 | } |
210 | 212 | ||
213 | int make_aux_task_if_required(struct task_struct *t) | ||
214 | { | ||
215 | struct task_struct *leader; | ||
216 | int retval = 0; | ||
217 | |||
218 | read_lock_irq(&tasklist_lock); | ||
219 | |||
220 | leader = t->group_leader; | ||
221 | |||
222 | if(!tsk_aux(leader)->initialized || !tsk_aux(leader)->aux_future) { | ||
223 | goto out; | ||
224 | } | ||
225 | |||
226 | TRACE_CUR("Making %s/%d in %s/%d an aux thread.\n", t->comm, t->pid, leader->comm, leader->pid); | ||
227 | |||
228 | INIT_LIST_HEAD(&tsk_rt(t)->aux_task_node); | ||
229 | INIT_BINHEAP_NODE(&tsk_rt(t)->aux_task_owner_node); | ||
230 | |||
231 | retval = admit_aux_task(t); | ||
232 | if (retval == 0) { | ||
233 | tsk_rt(t)->is_aux_task = 1; | ||
234 | |||
235 | #ifdef CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE | ||
236 | list_add_tail(&tsk_rt(t)->aux_task_node, &tsk_aux(leader)->aux_tasks); | ||
237 | |||
238 | if (!binheap_empty(&tsk_aux(leader)->aux_task_owners)) { | ||
239 | struct task_struct *hp = | ||
240 | container_of(binheap_top_entry(&tsk_aux(leader)->aux_task_owners, struct rt_param, aux_task_owner_node), | ||
241 | struct task_struct, rt_param); | ||
242 | |||
243 | TRACE_CUR("hp in group: %s/%d\n", hp->comm, hp->pid); | ||
244 | |||
245 | retval = litmus->__increase_prio(t, (tsk_rt(hp)->inh_task)? tsk_rt(hp)->inh_task : hp); | ||
246 | |||
247 | if (retval != 0) { | ||
248 | /* don't know how to recover from bugs with prio inheritance. better just crash. */ | ||
249 | read_unlock_irq(&tasklist_lock); | ||
250 | BUG(); | ||
251 | } | ||
252 | } | ||
253 | #endif | ||
254 | } | ||
255 | |||
256 | out: | ||
257 | read_unlock_irq(&tasklist_lock); | ||
258 | |||
259 | return retval; | ||
260 | } | ||
211 | 261 | ||
212 | 262 | ||
213 | long enable_aux_task_owner(struct task_struct *t) | 263 | long enable_aux_task_owner(struct task_struct *t) |
@@ -313,11 +363,12 @@ static int aux_task_owner_max_priority_order(struct binheap_node *a, | |||
313 | } | 363 | } |
314 | 364 | ||
315 | 365 | ||
316 | static long __do_enable_aux_tasks(void) | 366 | static long __do_enable_aux_tasks(int flags) |
317 | { | 367 | { |
318 | long retval = 0; | 368 | long retval = 0; |
319 | struct task_struct *leader; | 369 | struct task_struct *leader; |
320 | struct task_struct *t; | 370 | struct task_struct *t; |
371 | int aux_tasks_added = 0; | ||
321 | 372 | ||
322 | leader = current->group_leader; | 373 | leader = current->group_leader; |
323 | 374 | ||
@@ -327,34 +378,52 @@ static long __do_enable_aux_tasks(void) | |||
327 | tsk_aux(leader)->initialized = 1; | 378 | tsk_aux(leader)->initialized = 1; |
328 | } | 379 | } |
329 | 380 | ||
381 | if (flags & AUX_FUTURE) { | ||
382 | tsk_aux(leader)->aux_future = 1; | ||
383 | } | ||
384 | |||
330 | t = leader; | 385 | t = leader; |
331 | do { | 386 | do { |
332 | /* doesn't hurt to initialize them both */ | 387 | if (!tsk_rt(t)->has_aux_tasks && !tsk_rt(t)->is_aux_task) { |
333 | INIT_LIST_HEAD(&tsk_rt(t)->aux_task_node); | 388 | /* This may harmlessly reinit unused nodes. TODO: Don't reinit already init nodes. */ |
334 | INIT_BINHEAP_NODE(&tsk_rt(t)->aux_task_owner_node); | 389 | /* doesn't hurt to initialize both nodes */ |
390 | INIT_LIST_HEAD(&tsk_rt(t)->aux_task_node); | ||
391 | INIT_BINHEAP_NODE(&tsk_rt(t)->aux_task_owner_node); | ||
392 | } | ||
335 | 393 | ||
336 | TRACE_CUR("Checking task in %s/%d: %s/%d = (p = %llu):\n", | 394 | TRACE_CUR("Checking task in %s/%d: %s/%d = (p = %llu):\n", |
337 | leader->comm, leader->pid, t->comm, t->pid, | 395 | leader->comm, leader->pid, t->comm, t->pid, |
338 | tsk_rt(t)->task_params.period); | 396 | tsk_rt(t)->task_params.period); |
339 | 397 | ||
340 | /* inspect heap_node to see if it is an rt task */ | 398 | /* inspect period to see if it is an rt task */ |
341 | if (tsk_rt(t)->task_params.period == 0) { | 399 | if (tsk_rt(t)->task_params.period == 0) { |
342 | if (!tsk_rt(t)->is_aux_task) { | 400 | if (flags && AUX_CURRENT) { |
343 | TRACE_CUR("AUX task in %s/%d: %s/%d:\n", leader->comm, leader->pid, t->comm, t->pid); | 401 | if (!tsk_rt(t)->is_aux_task) { |
344 | /* hasn't been aux_tasks_increase_priorityted into rt. make it a aux. */ | 402 | int admit_ret; |
345 | tsk_rt(t)->is_aux_task = 1; | 403 | |
346 | 404 | TRACE_CUR("AUX task in %s/%d: %s/%d:\n", leader->comm, leader->pid, t->comm, t->pid); | |
405 | |||
406 | admit_ret = admit_aux_task(t); | ||
407 | |||
408 | if (admit_ret == 0) { | ||
409 | /* hasn't been aux_tasks_increase_priorityted into rt. make it a aux. */ | ||
410 | tsk_rt(t)->is_aux_task = 1; | ||
411 | aux_tasks_added = 1; | ||
412 | |||
347 | #ifdef CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE | 413 | #ifdef CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE |
348 | list_add_tail(&tsk_rt(t)->aux_task_node, &tsk_aux(leader)->aux_tasks); | 414 | list_add_tail(&tsk_rt(t)->aux_task_node, &tsk_aux(leader)->aux_tasks); |
349 | #endif | 415 | #endif |
350 | 416 | } | |
351 | (void)admit_aux_task(t); | 417 | } |
418 | else { | ||
419 | TRACE_CUR("AUX task in %s/%d is already set up: %s/%d\n", leader->comm, leader->pid, t->comm, t->pid); | ||
420 | } | ||
352 | } | 421 | } |
353 | else { | 422 | else { |
354 | TRACE_CUR("AUX task in %s/%d is already set up: %s/%d\n", leader->comm, leader->pid, t->comm, t->pid); | 423 | TRACE_CUR("Not changing thread in %s/%d to AUX task: %s/%d\n", leader->comm, leader->pid, t->comm, t->pid); |
355 | } | 424 | } |
356 | } | 425 | } |
357 | else { | 426 | else if (!tsk_rt(t)->is_aux_task) { /* don't let aux tasks get aux tasks of their own */ |
358 | if (!tsk_rt(t)->has_aux_tasks) { | 427 | if (!tsk_rt(t)->has_aux_tasks) { |
359 | TRACE_CUR("task in %s/%d: %s/%d:\n", leader->comm, leader->pid, t->comm, t->pid); | 428 | TRACE_CUR("task in %s/%d: %s/%d:\n", leader->comm, leader->pid, t->comm, t->pid); |
360 | tsk_rt(t)->has_aux_tasks = 1; | 429 | tsk_rt(t)->has_aux_tasks = 1; |
@@ -369,19 +438,18 @@ static long __do_enable_aux_tasks(void) | |||
369 | 438 | ||
370 | 439 | ||
371 | #ifdef CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE | 440 | #ifdef CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE |
372 | if (!binheap_empty(&tsk_aux(leader)->aux_task_owners)) { | 441 | if (aux_tasks_added && !binheap_empty(&tsk_aux(leader)->aux_task_owners)) { |
373 | struct task_struct *hp = container_of(binheap_top_entry(&tsk_aux(leader)->aux_task_owners, struct rt_param, aux_task_owner_node), | 442 | struct task_struct *hp = container_of(binheap_top_entry(&tsk_aux(leader)->aux_task_owners, struct rt_param, aux_task_owner_node), |
374 | struct task_struct, rt_param); | 443 | struct task_struct, rt_param); |
375 | TRACE_CUR("found hp in group: %s/%d\n", hp->comm, hp->pid); | 444 | TRACE_CUR("hp in group: %s/%d\n", hp->comm, hp->pid); |
376 | retval = aux_tasks_increase_priority(leader, | 445 | retval = aux_tasks_increase_priority(leader, (tsk_rt(hp)->inh_task)? tsk_rt(hp)->inh_task : hp); |
377 | (tsk_rt(hp)->inh_task)? tsk_rt(hp)->inh_task : hp); | ||
378 | } | 446 | } |
379 | #endif | 447 | #endif |
380 | 448 | ||
381 | return retval; | 449 | return retval; |
382 | } | 450 | } |
383 | 451 | ||
384 | static long __do_disable_aux_tasks(void) | 452 | static long __do_disable_aux_tasks(int flags) |
385 | { | 453 | { |
386 | long retval = 0; | 454 | long retval = 0; |
387 | struct task_struct *leader; | 455 | struct task_struct *leader; |
@@ -389,50 +457,56 @@ static long __do_disable_aux_tasks(void) | |||
389 | 457 | ||
390 | leader = current->group_leader; | 458 | leader = current->group_leader; |
391 | 459 | ||
392 | t = leader; | 460 | if (flags & AUX_FUTURE) { |
393 | do { | 461 | tsk_aux(leader)->aux_future = 0; |
394 | if (tsk_rt(t)->is_aux_task) { | 462 | } |
395 | 463 | ||
396 | TRACE_CUR("%s/%d is an aux task.\n", t->comm, t->pid); | 464 | if (flags & AUX_CURRENT) { |
397 | 465 | t = leader; | |
398 | if (is_realtime(t)) { | 466 | do { |
399 | long temp_retval; | 467 | if (tsk_rt(t)->is_aux_task) { |
400 | struct sched_param param = { .sched_priority = 0}; | 468 | |
401 | 469 | TRACE_CUR("%s/%d is an aux task.\n", t->comm, t->pid); | |
402 | TRACE_CUR("%s/%d is real-time. Changing policy to SCHED_NORMAL.\n", t->comm, t->pid); | 470 | |
403 | 471 | if (is_realtime(t)) { | |
404 | temp_retval = sched_setscheduler_nocheck(t, SCHED_NORMAL, ¶m); | 472 | long temp_retval; |
405 | 473 | struct sched_param param = { .sched_priority = 0}; | |
406 | if (temp_retval != 0) { | 474 | |
407 | TRACE_CUR("error changing policy of %s/%d to SCHED_NORMAL\n", t->comm, t->pid); | 475 | TRACE_CUR("%s/%d is real-time. Changing policy to SCHED_NORMAL.\n", t->comm, t->pid); |
408 | if (retval == 0) { | 476 | |
409 | retval = temp_retval; | 477 | temp_retval = sched_setscheduler_nocheck(t, SCHED_NORMAL, ¶m); |
410 | } | 478 | |
411 | else { | 479 | if (temp_retval != 0) { |
412 | TRACE_CUR("prior error (%d) masks new error (%d)\n", retval, temp_retval); | 480 | TRACE_CUR("error changing policy of %s/%d to SCHED_NORMAL\n", t->comm, t->pid); |
481 | if (retval == 0) { | ||
482 | retval = temp_retval; | ||
483 | } | ||
484 | else { | ||
485 | TRACE_CUR("prior error (%d) masks new error (%d)\n", retval, temp_retval); | ||
486 | } | ||
413 | } | 487 | } |
414 | } | 488 | } |
415 | } | ||
416 | 489 | ||
417 | tsk_rt(t)->is_aux_task = 0; | 490 | tsk_rt(t)->is_aux_task = 0; |
418 | } | 491 | } |
419 | t = next_thread(t); | 492 | t = next_thread(t); |
420 | } while(t != leader); | 493 | } while(t != leader); |
494 | } | ||
421 | 495 | ||
422 | return retval; | 496 | return retval; |
423 | } | 497 | } |
424 | 498 | ||
425 | asmlinkage long sys_set_aux_tasks(int enable) | 499 | asmlinkage long sys_set_aux_tasks(int flags) |
426 | { | 500 | { |
427 | long retval; | 501 | long retval; |
428 | 502 | ||
429 | read_lock_irq(&tasklist_lock); | 503 | read_lock_irq(&tasklist_lock); |
430 | 504 | ||
431 | if (enable) { | 505 | if (flags & AUX_ENABLE) { |
432 | retval = __do_enable_aux_tasks(); | 506 | retval = __do_enable_aux_tasks(flags); |
433 | } | 507 | } |
434 | else { | 508 | else { |
435 | retval = __do_disable_aux_tasks(); | 509 | retval = __do_disable_aux_tasks(flags); |
436 | } | 510 | } |
437 | 511 | ||
438 | read_unlock_irq(&tasklist_lock); | 512 | read_unlock_irq(&tasklist_lock); |
@@ -442,7 +516,7 @@ asmlinkage long sys_set_aux_tasks(int enable) | |||
442 | 516 | ||
443 | #else | 517 | #else |
444 | 518 | ||
445 | asmlinkage long sys_set_aux_tasks(int enable) | 519 | asmlinkage long sys_set_aux_tasks(int flags) |
446 | { | 520 | { |
447 | printk("Unsupported. Recompile with CONFIG_REALTIME_AUX_TASKS.\n"); | 521 | printk("Unsupported. Recompile with CONFIG_REALTIME_AUX_TASKS.\n"); |
448 | return -EINVAL; | 522 | return -EINVAL; |
diff --git a/litmus/edf_common.c b/litmus/edf_common.c index 5a3f5b417f73..c279bf12a7f5 100755 --- a/litmus/edf_common.c +++ b/litmus/edf_common.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <litmus/fpmath.h> | 22 | #include <litmus/fpmath.h> |
23 | #endif | 23 | #endif |
24 | 24 | ||
25 | #if defined(CONFIG_EDF_TIE_BREAK_HASH) || defined(CONFIG_REALTIME_AUX_TASKS) | 25 | #if defined(CONFIG_EDF_TIE_BREAK_HASH) |
26 | #include <linux/hash.h> | 26 | #include <linux/hash.h> |
27 | static inline long edf_hash(struct task_struct *t) | 27 | static inline long edf_hash(struct task_struct *t) |
28 | { | 28 | { |
@@ -43,23 +43,6 @@ static inline long edf_hash(struct task_struct *t) | |||
43 | } | 43 | } |
44 | #endif | 44 | #endif |
45 | 45 | ||
46 | #ifdef CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE | ||
47 | int aux_tie_break(struct task_struct *first, struct task_struct *second) | ||
48 | { | ||
49 | long fhash = edf_hash(first); | ||
50 | long shash = edf_hash(second); | ||
51 | if (fhash < shash) { | ||
52 | TRACE_CUR("%s/%d >> %s/%d --- %d\n", first->comm, first->pid, second->comm, second->pid, 1); | ||
53 | return 1; | ||
54 | } | ||
55 | else if(fhash == shash) { | ||
56 | TRACE_CUR("%s/%d >> %s/%d --- %d\n", first->comm, first->pid, second->comm, second->pid, (first->pid < second->pid)); | ||
57 | return first->pid < second->pid; | ||
58 | } | ||
59 | return 0; | ||
60 | } | ||
61 | #endif | ||
62 | |||
63 | 46 | ||
64 | /* edf_higher_prio - returns true if first has a higher EDF priority | 47 | /* edf_higher_prio - returns true if first has a higher EDF priority |
65 | * than second. Deadline ties are broken by PID. | 48 | * than second. Deadline ties are broken by PID. |
@@ -93,44 +76,47 @@ int edf_higher_prio(struct task_struct* first, struct task_struct* second) | |||
93 | 76 | ||
94 | #if defined(CONFIG_REALTIME_AUX_TASK_PRIORITY_BOOSTED) | 77 | #if defined(CONFIG_REALTIME_AUX_TASK_PRIORITY_BOOSTED) |
95 | /* run aux tasks at max priority */ | 78 | /* run aux tasks at max priority */ |
79 | /* TODO: Actually use prio-boosting. */ | ||
96 | if (first->rt_param.is_aux_task != second->rt_param.is_aux_task) | 80 | if (first->rt_param.is_aux_task != second->rt_param.is_aux_task) |
97 | { | 81 | { |
98 | return (first->rt_param.is_aux_task > second->rt_param.is_aux_task); | 82 | return (first->rt_param.is_aux_task > second->rt_param.is_aux_task); |
99 | } | 83 | } |
100 | else if(first->rt_param.is_aux_task && second->rt_param.is_aux_task) | 84 | else if(first->rt_param.is_aux_task && second->rt_param.is_aux_task) |
101 | { | 85 | { |
86 | if(first->group_leader == second->group_leader) { | ||
87 | TRACE_CUR("aux tie break!\n"); // tie-break by BASE priority of the aux tasks | ||
88 | goto aux_tie_break; | ||
89 | } | ||
102 | first = first->group_leader; | 90 | first = first->group_leader; |
103 | second = second->group_leader; | 91 | second = second->group_leader; |
104 | } | 92 | } |
105 | #elif defined(CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE) | 93 | #elif defined(CONFIG_REALTIME_AUX_TASK_PRIORITY_INHERITANCE) |
106 | { | 94 | { |
107 | int first_lo_aux, second_lo_aux; | 95 | int first_lo_aux = first->rt_param.is_aux_task && !first->rt_param.inh_task; |
108 | int first_hi_aux, second_hi_aux; | 96 | int second_lo_aux = second->rt_param.is_aux_task && !second->rt_param.inh_task; |
109 | first_lo_aux = first->rt_param.is_aux_task && !first->rt_param.inh_task; | 97 | |
110 | second_lo_aux = second->rt_param.is_aux_task && !second->rt_param.inh_task; | 98 | /* prioritize aux tasks without inheritance below real-time tasks */ |
111 | 99 | if (first_lo_aux || second_lo_aux) { | |
112 | if (first_lo_aux && !second_lo_aux) { | 100 | // one of these is an aux task without inheritance. |
113 | TRACE_CUR("%s/%d >> %s/%d --- 0\n", first->comm, first->pid, second->comm, second->pid); | 101 | if(first_lo_aux && second_lo_aux) { |
114 | return 0; | 102 | TRACE_CUR("aux tie break!\n"); // tie-break by BASE priority of the aux tasks |
115 | } | 103 | goto aux_tie_break; |
116 | else if (second_lo_aux && !first_lo_aux) { | 104 | } |
117 | TRACE_CUR("%s/%d >> %s/%d --- 1\n", first->comm, first->pid, second->comm, second->pid); | 105 | else { |
118 | return 1; | 106 | // make the aux thread lowest priority real-time task |
119 | } | 107 | int temp = (first_lo_aux) ? !is_realtime(second) : !is_realtime(first); |
120 | else if (first_lo_aux && second_lo_aux) { | 108 | TRACE_CUR("%s/%d >> %s/%d --- %d\n", first->comm, first->pid, second->comm, second->pid, temp); |
121 | int aux_lo_tie_break = aux_tie_break(first, second); | 109 | return temp; |
122 | TRACE_CUR("low aux tie break: %s/%d >> %s/%d --- %d\n", first->comm, first->pid, second->comm, second->pid, aux_lo_tie_break); | 110 | } |
123 | return aux_lo_tie_break; | 111 | } |
124 | } | 112 | |
125 | 113 | if (first->rt_param.is_aux_task && second->rt_param.is_aux_task && | |
126 | first_hi_aux = first->rt_param.is_aux_task && first->rt_param.inh_task; | 114 | first->rt_param.inh_task == second->rt_param.inh_task) { // inh_task is !NULL for both tasks since neither was a lo_aux task |
127 | second_hi_aux = second->rt_param.is_aux_task && second->rt_param.inh_task; | 115 | // Both aux tasks inherit from the same task, so tie-break |
128 | 116 | // by base priority of the aux tasks. | |
129 | if (first_hi_aux && second_hi_aux && first->rt_param.inh_task == second->rt_param.inh_task) { | 117 | TRACE_CUR("aux tie break!\n"); |
130 | int aux_hi_tie_break = aux_tie_break(first, second); | 118 | goto aux_tie_break; |
131 | TRACE_CUR("hi aux tie break: %s/%d >> %s/%d --- %d\n", first->comm, first->pid, second->comm, second->pid, aux_hi_tie_break); | 119 | } |
132 | return aux_hi_tie_break; | ||
133 | } | ||
134 | } | 120 | } |
135 | #endif | 121 | #endif |
136 | 122 | ||
@@ -174,6 +160,8 @@ int edf_higher_prio(struct task_struct* first, struct task_struct* second) | |||
174 | 160 | ||
175 | #endif | 161 | #endif |
176 | 162 | ||
163 | aux_tie_break: | ||
164 | |||
177 | if (!is_realtime(second_task)) { | 165 | if (!is_realtime(second_task)) { |
178 | return 1; | 166 | return 1; |
179 | } | 167 | } |
diff --git a/litmus/litmus.c b/litmus/litmus.c index cfd14852502b..8bc159b2fcce 100644..100755 --- a/litmus/litmus.c +++ b/litmus/litmus.c | |||
@@ -634,6 +634,14 @@ void litmus_fork(struct task_struct* p) | |||
634 | p->od_table = NULL; | 634 | p->od_table = NULL; |
635 | } | 635 | } |
636 | 636 | ||
637 | /* Called right before copy_process() returns a forked thread. */ | ||
638 | void litmus_post_fork_thread(struct task_struct* p) | ||
639 | { | ||
640 | #ifdef CONFIG_REALTIME_AUX_TASKS | ||
641 | make_aux_task_if_required(p); | ||
642 | #endif | ||
643 | } | ||
644 | |||
637 | /* Called upon execve(). | 645 | /* Called upon execve(). |
638 | * current is doing the exec. | 646 | * current is doing the exec. |
639 | * Don't let address space specific stuff leak. | 647 | * Don't let address space specific stuff leak. |