diff options
Diffstat (limited to 'litmus/aux_tasks.c')
-rwxr-xr-x | litmus/aux_tasks.c | 198 |
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) | |||
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; |