aboutsummaryrefslogtreecommitdiffstats
path: root/include/litmus/sched_mc.h
blob: 740cc11be5d737e7b4cd5717fa360f8a5a5cda8d (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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#ifndef _LINUX_SCHED_MC_H_
#define _LINUX_SCHED_MC_H_

/* criticality levels */
enum crit_level {
	/* probably don't need to assign these (paranoid) */
	CRIT_LEVEL_A = 0,
	CRIT_LEVEL_B = 1,
	CRIT_LEVEL_C = 2,
	NUM_CRIT_LEVELS = 3,
};

struct mc_task {
	enum crit_level crit;
	int lvl_a_id;
	int lvl_a_eligible;
};

struct mc_job {
	int is_ghost:1;
	lt_t ghost_budget;
};

#ifdef __KERNEL__
/*
 * These are used only in the kernel. Userspace programs like RTSpin won't see
 * them.
 */
struct mc_data {
	struct mc_task mc_task;
	struct mc_job mc_job;
};

#define tsk_mc_data(t)	 (tsk_rt(t)->mc_data)
#define tsk_mc_crit(t)	 (tsk_mc_data(t)->mc_task.crit)
#define is_ghost(t)	 (tsk_mc_data(t)->mc_job.is_ghost)

#define TS "(%s/%d:%d:%s)"
#define TA(t) (t) ? tsk_mc_data(t) ? is_ghost(t) ? "ghost" : t->comm \
						 : t->comm : "NULL", \
	      (t) ? t->pid : 1,					\
	      (t) ? t->rt_param.job_params.job_no : 1,		\
	      (t && get_task_domain(t)) ? get_task_domain(t)->name : ""
#define STRACE(fmt, args...) \
	sched_trace_log_message("%d P%d      [%s@%s:%d]: " fmt,	\
				TRACE_ARGS,  ## args)
#define TRACE_MC_TASK(t, fmt, args...)				\
	STRACE(TS " " fmt, TA(t), ##args)

/*
 * The MC-CE scheduler uses this as domain data.
 */
struct ce_dom_data {
	int cpu;
	struct task_struct *scheduled, *should_schedule;
#ifdef CONFIG_MERGE_TIMERS
	struct rt_event event;
#else
	struct hrtimer_start_on_info timer_info;
	struct hrtimer timer;
#endif
};

/**
 * enum crit_state - Logically add / remove CPUs from criticality levels.
 *
 * Global crit levels need to use a two step process to remove CPUs so
 * that the CPUs can be removed without holding domain locks.
 *
 * @CS_ACTIVE	The criticality entry can run a task
 * @CS_ACTIVATE The criticality entry can run a task, but hasn't had its
 *		position updated in a global heap. Set with ONLY CPU lock.
 * @CS_REMOVE   The criticality entry is logically removed, but hasn't had its
 *		position adjusted in a global heap. This should be set when
 *		ONLY the CPU state is locked.
 * @CS_REMOVED	The criticality entry has been removed from the crit level
 */
enum crit_state { CS_ACTIVE, CS_ACTIVATE, CS_REMOVE, CS_REMOVED };

/**
 * struct crit_entry - State of a CPU within each criticality level system.
 * @level	Criticality level of this entry
 * @linked	Logically running task, ghost or regular
 * @domain	Domain from which to draw tasks
 * @usable	False if a higher criticality task is running
 * @event	For ghost task budget enforcement (merge timers)
 * @timer	For ghost task budget enforcement (not merge timers)
 * @node	Used to sort crit_entries by preemptability in global domains
 */
struct crit_entry {
	enum crit_level		level;
	struct task_struct*	linked;
	struct domain*		domain;
	enum crit_state		state;
#ifdef CONFIG_MERGE_TIMERS
	struct rt_event		event;
#else
	struct hrtimer		timer;
#endif
	struct bheap_node*	node;
};

/**
 * struct domain_data - Wrap domains with related CPU state
 * @domain	A domain for a criticality level
 * @heap	The preemptable heap of crit entries (for global domains)
 * @crit_entry	The crit entry for this domain (for partitioned domains)
 */
struct domain_data {
	struct domain 		domain;
	struct bheap*		heap;
	struct crit_entry*	crit_entry;
};

/*
 * Functions that are used with the MC-CE plugin.
 */
long mc_ce_set_domains(const int, struct domain_data*[]);
unsigned int mc_ce_get_expected_job(const int, const int);

/*
 * These functions are (lazily) inserted into the MC plugin code so that it
 * manipulates the MC-CE state.
 */
long mc_ce_admit_task_common(struct task_struct*);
void mc_ce_task_exit_common(struct task_struct*);
lt_t mc_ce_timer_callback_common(domain_t*);
void mc_ce_release_at_common(struct task_struct*, lt_t);
long mc_ce_activate_plugin_common(void);
long mc_ce_deactivate_plugin_common(void);

#endif /* __KERNEL__ */

#endif