aboutsummaryrefslogblamecommitdiffstats
path: root/litmus/edf_common.c
blob: 6ed927fcce6de61c55af26a386716be6787b5a7e (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16















                                            










                                                                       


















                                                                            





                                        


                                                      
                                               
                                                      
                                                

                                                        

















                                                                       





                                                             
                                                                      
                                                                         


                                                                
                                                      







                                                                       

 
                                                               
 
                                                             




























                                                                               
/*
 * kernel/edf_common.c
 *
 * Common functions for EDF based scheduler.
 */

#include <linux/percpu.h>
#include <linux/sched.h>
#include <linux/list.h>

#include <litmus/litmus.h>
#include <litmus/sched_plugin.h>
#include <litmus/sched_trace.h>

#include <litmus/edf_common.h>

#ifdef DONT_PREEMPT_ON_TIE
static inline cur_sched_higher_prio(
	struct task_struct* first,
	struct task_struct* second)
{
	int first_is_sched = (tsk_rt(first)->scheduled_on != NO_CPU);
	int second_is_sched = (tsk_rt(second)->scheduled_on != NO_CPU);
	return(first_is_sched > second_is_sched);
}
#endif

/* edf_higher_prio -  returns true if first has a higher EDF priority
 *                    than second. Deadline ties are broken by PID.
 *
 * both first and second may be NULL
 */
int edf_higher_prio(struct task_struct* first,
		    struct task_struct* second)
{
	struct task_struct *first_task = first;
	struct task_struct *second_task = second;

	/* There is no point in comparing a task to itself. */
	if (first && first == second) {
		TRACE_TASK(first,
			   "WARNING: pointless edf priority comparison.\n");
		return 0;
	}


	/* check for NULL tasks */
	if (!first || !second)
		return first && !second;

#ifdef CONFIG_LITMUS_LOCKING

	/* Check for inherited priorities. Change task
	 * used for comparison in such a case.
	 */
	if (unlikely(first->rt_param.inh_task))
		first_task = first->rt_param.inh_task;
	if (unlikely(second->rt_param.inh_task))
		second_task = second->rt_param.inh_task;

	/* Check for priority boosting. Tie-break by start of boosting.
	 */
	if (unlikely(is_priority_boosted(first_task))) {
		/* first_task is boosted, how about second_task? */
		if (!is_priority_boosted(second_task) ||
		    lt_before(get_boost_start(first_task),
			      get_boost_start(second_task)))
			return 1;
		else
			return 0;
	} else if (unlikely(is_priority_boosted(second_task)))
		/* second_task is boosted, first is not*/
		return 0;

#endif


	return !is_realtime(second_task)  ||

		/* is the deadline of the first task earlier?
		 * Then it has higher priority.
		 */
		earlier_deadline(first_task, second_task) ||

		/* tie-break order: cur scheduled, pid, inheritance */
		(get_deadline(first_task) == get_deadline(second_task) &&
#ifdef DONT_PREEMPT_ON_TIE
		 	(cur_sched_higher_prio(first, second) ||
#endif
	        (first_task->pid < second_task->pid ||
				(first_task->pid == second_task->pid &&
		 			!second->rt_param.inh_task
				)
			)
#ifdef DONT_PREEMPT_ON_TIE
			)
#endif
		);
}

int edf_ready_order(struct bheap_node* a, struct bheap_node* b)
{
	return edf_higher_prio(bheap2task(a), bheap2task(b));
}

void edf_domain_init(rt_domain_t* rt, check_resched_needed_t resched,
		      release_jobs_t release)
{
	rt_domain_init(rt,  edf_ready_order, resched, release);
}

/* need_to_preempt - check whether the task t needs to be preempted
 *                   call only with irqs disabled and with  ready_lock acquired
 *                   THIS DOES NOT TAKE NON-PREEMPTIVE SECTIONS INTO ACCOUNT!
 */
int edf_preemption_needed(rt_domain_t* rt, struct task_struct *t)
{
	/* we need the read lock for edf_ready_queue */
	/* no need to preempt if there is nothing pending */
	if (!__jobs_pending(rt))
		return 0;
	/* we need to reschedule if t doesn't exist */
	if (!t)
		return 1;

	/* NOTE: We cannot check for non-preemptibility since we
	 *       don't know what address space we're currently in.
	 */

	/* make sure to get non-rt stuff out of the way */
	return !is_realtime(t) || edf_higher_prio(__next_ready(rt), t);
}