aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/aux_tasks.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/aux_tasks.c')
-rwxr-xr-xlitmus/aux_tasks.c198
1 files changed, 136 insertions, 62 deletions
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)
44int exit_aux_task(struct task_struct *t) 44int 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
213int 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
256out:
257 read_unlock_irq(&tasklist_lock);
258
259 return retval;
260}
211 261
212 262
213long enable_aux_task_owner(struct task_struct *t) 263long 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
316static long __do_enable_aux_tasks(void) 366static 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
384static long __do_disable_aux_tasks(void) 452static 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, &param); 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, &param);
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
425asmlinkage long sys_set_aux_tasks(int enable) 499asmlinkage 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
445asmlinkage long sys_set_aux_tasks(int enable) 519asmlinkage 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;