diff options
Diffstat (limited to 'litmus')
-rw-r--r-- | litmus/sched_gsn_edf.c | 75 |
1 files changed, 72 insertions, 3 deletions
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index cbde657ce7..53538e2eb2 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -600,6 +600,72 @@ static void gsnedf_task_exit(struct task_struct * t) | |||
600 | } | 600 | } |
601 | 601 | ||
602 | #ifdef CONFIG_FMLP | 602 | #ifdef CONFIG_FMLP |
603 | |||
604 | /* Update the queue position of a task that got it's priority boosted via | ||
605 | * priority inheritance. */ | ||
606 | static void update_queue_position(struct task_struct *holder) | ||
607 | { | ||
608 | /* We don't know whether holder is in the ready queue. It should, but | ||
609 | * on a budget overrun it may already be in a release queue. Hence, | ||
610 | * calling unlink() is not possible since it assumes that the task is | ||
611 | * not in a release queue. However, we can safely check whether | ||
612 | * sem->holder is currently in a queue or scheduled after locking both | ||
613 | * the release and the ready queue lock. */ | ||
614 | |||
615 | /* Assumption: caller holds gsnedf_lock */ | ||
616 | |||
617 | int check_preempt = 0; | ||
618 | |||
619 | if (tsk_rt(holder)->linked_on != NO_CPU) { | ||
620 | TRACE_TASK(holder, "%s: linked on %d\n", | ||
621 | __FUNCTION__, tsk_rt(holder)->linked_on); | ||
622 | /* Holder is scheduled; need to re-order CPUs. | ||
623 | * We can't use heap_decrease() here since | ||
624 | * the cpu_heap is ordered in reverse direction, so | ||
625 | * it is actually an increase. */ | ||
626 | heap_delete(cpu_lower_prio, &gsnedf_cpu_heap, | ||
627 | gsnedf_cpus[tsk_rt(holder)->linked_on]->hn); | ||
628 | heap_insert(cpu_lower_prio, &gsnedf_cpu_heap, | ||
629 | gsnedf_cpus[tsk_rt(holder)->linked_on]->hn); | ||
630 | } else { | ||
631 | /* holder may be queued: first stop queue changes */ | ||
632 | spin_lock(&gsnedf.release_lock); | ||
633 | if (is_queued(holder)) { | ||
634 | TRACE_TASK(holder, "%s: is queued\n", | ||
635 | __FUNCTION__); | ||
636 | /* We need to update the position | ||
637 | * of holder in some heap. Note that this | ||
638 | * may be a release heap. */ | ||
639 | check_preempt = | ||
640 | !heap_decrease(edf_ready_order, | ||
641 | tsk_rt(holder)->heap_node); | ||
642 | } else { | ||
643 | /* Nothing to do: if it is not queued and not linked | ||
644 | * then it is currently being moved by other code | ||
645 | * (e.g., a timer interrupt handler) that will use the | ||
646 | * correct priority when enqueuing the task. */ | ||
647 | TRACE_TASK(holder, "%s: is NOT queued => Done.\n", | ||
648 | __FUNCTION__); | ||
649 | } | ||
650 | spin_unlock(&gsnedf.release_lock); | ||
651 | |||
652 | /* If holder was enqueued in a release heap, then the following | ||
653 | * preemption check is pointless, but we can't easily detect | ||
654 | * that case. If you want to fix this, then consider that | ||
655 | * simply adding a state flag requires O(n) time to update when | ||
656 | * releasing n tasks, which conflicts with the goal to have | ||
657 | * O(log n) merges. */ | ||
658 | if (check_preempt) { | ||
659 | /* heap_decrease() hit the top level of the heap: make | ||
660 | * sure preemption checks get the right task, not the | ||
661 | * potentially stale cache. */ | ||
662 | heap_uncache_min(edf_ready_order, | ||
663 | &gsnedf.ready_queue); | ||
664 | check_for_preemptions(); | ||
665 | } | ||
666 | } | ||
667 | } | ||
668 | |||
603 | static long gsnedf_pi_block(struct pi_semaphore *sem, | 669 | static long gsnedf_pi_block(struct pi_semaphore *sem, |
604 | struct task_struct *new_waiter) | 670 | struct task_struct *new_waiter) |
605 | { | 671 | { |
@@ -613,16 +679,19 @@ static long gsnedf_pi_block(struct pi_semaphore *sem, | |||
613 | BUG_ON(!new_waiter); | 679 | BUG_ON(!new_waiter); |
614 | 680 | ||
615 | if (edf_higher_prio(new_waiter, sem->hp.task)) { | 681 | if (edf_higher_prio(new_waiter, sem->hp.task)) { |
616 | TRACE_TASK(new_waiter, " boosts priority\n"); | 682 | TRACE_TASK(new_waiter, " boosts priority via %p\n", sem); |
617 | /* called with IRQs disabled */ | 683 | /* called with IRQs disabled */ |
618 | spin_lock(&gsnedf_lock); | 684 | spin_lock(&gsnedf_lock); |
619 | /* store new highest-priority task */ | 685 | /* store new highest-priority task */ |
620 | sem->hp.task = new_waiter; | 686 | sem->hp.task = new_waiter; |
621 | if (sem->holder) { | 687 | if (sem->holder) { |
688 | TRACE_TASK(sem->holder, | ||
689 | " holds %p and will inherit from %s/%d\n", | ||
690 | sem, | ||
691 | new_waiter->comm, new_waiter->pid); | ||
622 | /* let holder inherit */ | 692 | /* let holder inherit */ |
623 | sem->holder->rt_param.inh_task = new_waiter; | 693 | sem->holder->rt_param.inh_task = new_waiter; |
624 | unlink(sem->holder); | 694 | update_queue_position(sem->holder); |
625 | gsnedf_job_arrival(sem->holder); | ||
626 | } | 695 | } |
627 | spin_unlock(&gsnedf_lock); | 696 | spin_unlock(&gsnedf_lock); |
628 | } | 697 | } |