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
|
/* litmus/jobs.c - common job control code
* TODO: modified heavily for sched_mc
*/
#include <linux/sched.h>
#include <litmus/litmus.h>
#include <litmus/jobs.h>
#include <litmus/trace.h>
#include <litmus/sched_trace.h>
#include <litmus/domain.h>
#ifdef CONFIG_MERGE_TIMERS
#include <litmus/event_group.h>
#endif
#ifdef CONFIG_PLUGIN_MC
#include <litmus/sched_mc.h>
#else
#define TRACE_MC_TASK(t, fmt, args...) TRACE_TASK(t, fmt, ##args)
#endif
static inline void setup_release(struct task_struct *t, struct rt_job *job,
lt_t release)
{
/* prepare next release */
job->release = release;
job->deadline = release + get_rt_relative_deadline(t);
job->exec_time = 0;
/* update job sequence number */
++job->job_no;
}
static inline void setup_kernel_release(struct task_struct *t, lt_t release)
{
BUG_ON(!t);
/* Record lateness before we set up the next job's
* release and deadline. Lateness may be negative.
*/
t->rt_param.job_params.lateness =
(long long)litmus_clock() -
(long long)t->rt_param.job_params.deadline;
t->rt.time_slice = 1;
setup_release(t, &tsk_rt(t)->job_params, release);
TRACE_MC_TASK(t, "kernel rel=%llu, dead=%llu\n", get_release(t), get_deadline(t));
sched_trace_server_release(-t->pid, get_rt_job(t),
tsk_rt(t)->job_params);
}
void setup_user_release(struct task_struct *t, lt_t release)
{
setup_release(t, &tsk_rt(t)->user_job, release);
TRACE_MC_TASK(t, "user rel=%llu, dead=%llu\n", get_user_release(t), get_user_deadline(t));
#ifdef CONFIG_PLUGIN_MC
if (CRIT_LEVEL_A != tsk_mc_crit(t))
sched_trace_task_release(t);
#endif
}
void prepare_for_next_period(struct task_struct *t)
{
setup_kernel_release(t, get_release(t) + get_rt_period(t));
}
void release_at(struct task_struct *t, lt_t start)
{
BUG_ON(!t);
TRACE_MC_TASK(t, "Releasing at %llu\n", start);
setup_kernel_release(t, start);
setup_user_release(t, start);
BUG_ON(!is_released(t, start));
set_rt_flags(t, RT_F_RUNNING);
}
/*
* User-space job has completed execution
*/
long complete_job(void)
{
lt_t amount;
lt_t now = litmus_clock();
lt_t exec_time = tsk_rt(current)->job_params.exec_time;
/* Task statistic summaries */
tsk_rt(current)->tot_exec_time += exec_time;
if (lt_before(tsk_rt(current)->max_exec_time, exec_time))
tsk_rt(current)->max_exec_time = exec_time;
if (is_tardy(current, now)) {
TRACE_TASK(current, "is tardy, now: %llu, deadline: %llu\n",
now, get_deadline(current));
amount = now - get_deadline(current);
if (lt_after(amount, tsk_rt(current)->max_tardy))
tsk_rt(current)->max_tardy = amount;
tsk_rt(current)->total_tardy += amount;
++tsk_rt(current)->missed;
}
/* Mark that we do not execute anymore */
set_rt_flags(current, RT_F_SLEEP);
/* call schedule, this will return when a new job arrives
* it also takes care of preparing for the next release
*/
schedule();
return 0;
}
|