aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/fifo_common.c
blob: c1641a16a294b9b639cdd368b47b7ed32f5ba8e2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/*
 * kernel/fifo_common.c
 *
 * Fifo helper functions. Could one day be  a FIFO plugin if someone
 * is interested.
 *
 * The current FIFO implementaion automatically chops Linux tasks into 
 * smaller jobs by assigning a fixed time slice. Once that time slice expires,
 * it is treated as a new job release (that is queued in the back). 
 * 
 * The result is that it provides FIFO properties on a job level and round-robin
 * on a task level if the tasks execute continuously.
 */

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

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

/* This function is defined in sched.c. We need access it for 
 * indirect switching.
 */
void __activate_task(struct task_struct *p, runqueue_t *rq);

/* fifo_higher_prio -  returns true if first has a higher FIFO priority
 *                    than second. Release time ties are broken by PID.
 *
 * first first must not be NULL and a real-time task.
 * second may be NULL or a non-rt task.
 */
int fifo_higher_prio(struct task_struct* first, 
		     struct task_struct* second) 
{
	struct task_struct *first_task = first;
	struct task_struct *second_task = second;

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

	return 
		/* does the second task exist and is it a real-time task?  If
		 * not, the first task (which is a RT task) has higher
		 * priority.
		 */
		!second_task || !is_realtime(second_task)  ||
		
		/* is the release of the first task earlier?
		 * Then it has higher priority.
		 */
		earlier_last_release(first_task, second_task) ||

		/* Do we have a release time tie? 
		 * Then break by PID.
		 */
		(get_last_release(first_task) == 
		 get_last_release(second_task) && 
	        (first_task->pid < second_task->pid ||
		 
		/* If the PIDs are the same then the task with the inherited 
		 * priority wins.
		 */
		(first_task->pid == second_task->pid &&
		 !second->rt_param.inh_task)));
}

int fifo_ready_order(struct list_head* a, struct list_head* b)
{
	return fifo_higher_prio(
		list_entry(a, struct task_struct, rt_list),
		list_entry(b, struct task_struct, rt_list));
}

void fifo_domain_init(rt_domain_t* rt, check_resched_needed_t resched)
{
	rt_domain_init(rt, resched, fifo_ready_order);	
}