aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/jobs.c
blob: 6ba40db9639fc180e371292786d98e6a328a6e4f (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
/* 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;
}