aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--litmus/sched_gsn_edf.c75
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. */
606static 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
603static long gsnedf_pi_block(struct pi_semaphore *sem, 669static 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 }