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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
|
/*
* Definition of the scheduler plugin interface.
*
*/
#ifndef _LINUX_RT_PARAM_H_
#define _LINUX_RT_PARAM_H_
#include <linux/wait.h>
typedef unsigned long jiffie_t;
/* different types of clients */
typedef enum {
RT_CLASS_HARD,
RT_CLASS_SOFT,
RT_CLASS_BEST_EFFORT
} task_class_t;
typedef struct rt_param {
unsigned long exec_cost;
unsigned long period;
unsigned int cpu;
task_class_t class;
} rt_param_t;
/* fixed point wrapper to force compiler
* errors in case of misuse of a fixed point value
*/
typedef struct
{
long long val;
} fp_t;
typedef struct {
fp_t weight;
unsigned long period;
fp_t value;
} service_level_t;
typedef struct {
fp_t error;
fp_t estimate;
fp_t accumulated;
} predictor_state_t;
typedef struct {
/* when will this task be release the next time? */
jiffie_t release;
/* time instant the last job was released */
jiffie_t last_release;
/* what is the current deadline? */
jiffie_t deadline;
/* b-bit tie breaker for PFAIR, it is ignored in EDF */
int b_bit;
/* group deadline tie breaker, it is ignored in EDF */
jiffie_t group_deadline;
/* how long has this task executed so far?
* In case of capacity sharing a job completion cannot be
* detected by checking time_slice == 0 as the job may have
* executed while using another capacity. Use this counter
* to keep track of the time spent on a CPU by a job.
*
* In other words: The number of consumed quanta since the
* last job release.
*/
unsigned int exec_time;
/* Which job is this. This is used to let user space
* specify which job to wait for, which is important if jobs
* overrun. If we just call sys_sleep_next_period() then we
* will unintentionally miss jobs after an overrun.
*
* Increase this sequence number when a job is released.
*/
unsigned int job_no;
} rt_times_t;
/* RT task parameters for scheduling extensions
* These parameters are inherited during clone and therefore must
* be explicitly set up before the task set is launched.
*/
typedef struct task_rt_param {
/* Real-time marker: 1 iff it is a LITMUS real-time task.
*/
int is_realtime:1;
/* is this task under control of litmus?
` *
* this is necessary because otherwise signal delivery code
* may try to wake up a task that is already queued in plugin
* data structures.
*/
int litmus_controlled:1;
/* Did this task register any SRP controlled resource accesses?
* This, of course, should only ever be true under partitioning.
* However, this limitation is not currently enforced.
*/
int subject_to_srp:1;
/* This bit will be set if the task should be killed once all scheduler
* locks have been dropped. We can't kill it directly since the signal
* handling code acquires locks that are also acquired with interrupts
* enabled, thus we first need to drop the scheduler locks.
*/
int must_die:1;
/* user controlled parameters */
rt_param_t basic_params;
/* is the task sleeping? */
unsigned int flags;
/* task representing the current "inherited" task
* priority, assigned by inherit_priority and
* return priority in the scheduler plugins.
* could point to self if PI does not result in
* an increased task priority.
*/
struct task_struct* inh_task;
/* Don't just dereference this pointer in kernel space!
* It might very well point to junk or nothing at all.
* NULL indicates that the task has not requested any non-preemptable
* section support.
* TODO: What happens on fork?
*/
__user short* np_flag;
/* For the FMLP under PSN-EDF, it is required to make the task
* non-preemptive from kernel space. In order not to interfere with
* user space, this counter indicates the kernel space np setting.
* kernel_np > 0 => task is non-preemptive
*/
unsigned int kernel_np;
/* timing parameters */
rt_times_t times;
/* This is currently only used by the PFAIR code
* and a prime candidate for cleanup.
*/
rt_times_t backup;
/* This field can be used by plugins to store where the task
* is currently scheduled. It is the responsibility of the
* plugin to avoid race conditions.
*
* Used by GSN-EDF.
*/
int scheduled_on;
/* This field can be used by plugins to store where the task
* is currently linked. It is the responsibility of the plugin
* to avoid race conditions.
*
* Used by GSN-EDF.
*/
int linked_on;
/* Adaptive support. Adaptive tasks will store service levels
* in this (dynamically allocated) structure.
*/
service_level_t* service_level;
unsigned int no_service_levels;
unsigned int cur_service_level;
/* Adaptive support. Store state for weight estimation.
*/
predictor_state_t predictor_state;
} task_rt_param_t;
/* Possible RT flags */
#define RT_F_RUNNING 0x00000000
#define RT_F_SLEEP 0x00000001
#define RT_F_EXP_QUANTA 0x00000002
#define RT_F_NON_PREEMTABLE 0x00000004
#define RT_F_EXIT_SEM 0x00000008
/* Realtime utility macros */
#define get_passed_quanta(t) ((t)->rt_param.times.exec_time)
#define inc_passed_quanta(t) ((t)->rt_param.times.exec_time += 1)
#define get_rt_flags(t) ((t)->rt_param.flags)
#define set_rt_flags(t,f) (t)->rt_param.flags=(f)
#define get_exec_cost(t) ((t)->rt_param.basic_params.exec_cost)
#define get_rt_period(t) ((t)->rt_param.basic_params.period)
#define set_rt_period(t,p) (t)->rt_param.basic_params.period=(p)
#define set_exec_cost(t,e) (t)->rt_param.basic_params.exec_cost=(e)
#define get_partition(t) (t)->rt_param.basic_params.cpu
#define get_deadline(t) ((t)->rt_param.times.deadline)
#define get_class(t) ((t)->rt_param.basic_params.class)
#define get_est_weight(t) ((t)->rt_param.predictor_state.estimate)
#define is_realtime(t) ((t)->rt_param.is_realtime)
#define is_subject_to_srp(t) ((t)->rt_param.subject_to_srp)
#define is_hrt(t) \
((t)->rt_param.basic_params.class == RT_CLASS_HARD)
#define is_srt(t) \
((t)->rt_param.basic_params.class == RT_CLASS_SOFT)
#define is_be(t) \
((t)->rt_param.basic_params.class == RT_CLASS_BEST_EFFORT)
#define clear_rt_params(t) \
memset(&(t)->rt_param,0, sizeof(struct task_rt_param))
#define get_last_release_time(t) ((t)->rt_param.times.last_release)
#define set_last_release_time(t,r) ((t)->rt_param.times.last_release=(r))
#define get_release(t) ((t)->rt_param.times.release)
#define set_release(t,r) ((t)->rt_param.times.release=(r))
#define get_last_release(t) ((t)->rt_param.times.last_release)
/* honor the flag that is set when scheduling is in progress
* This is some dirty hack in Linux that creates race conditions in our code
* if we don't pay attention to it.
*/
#define is_running(t) \
((t)->state == TASK_RUNNING || \
(t)->thread_info->preempt_count & PREEMPT_ACTIVE)
#define is_blocked(t) (!is_running(t))
#define is_released(t) (time_before_eq((t)->rt_param.times.release, jiffies))
#define is_tardy(t) (time_before_eq((t)->rt_param.times.deadline, jiffies))
#define task_slack(t) ( (int) (t)->rt_param.times.deadline - (int) jiffies - \
(int) ((t)->rt_param.basic_params.exec_cost - \
(t)->rt_param.times.exec_time))
/* real-time comparison macros */
#define earlier_deadline(a, b) (time_before(\
(a)->rt_param.times.deadline,\
(b)->rt_param.times.deadline))
#define earlier_release(a, b) (time_before(\
(a)->rt_param.times.release,\
(b)->rt_param.times.release))
#define earlier_last_release(a, b) (time_before(\
(a)->rt_param.times.last_release,\
(b)->rt_param.times.last_release))
#define make_np(t) do {t->rt_param.kernel_np++;} while(0);
#define take_np(t) do {t->rt_param.kernel_np--;} while(0);
#define backup_times(t) do { (t)->rt_param.backup=(t)->rt_param.times; \
} while(0);
#define restore_times(t) do { (t)->rt_param.times=(t)->rt_param.backup; \
} while(0);
#endif
|