aboutsummaryrefslogtreecommitdiffstats
path: root/src/litmus.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/litmus.c')
-rw-r--r--src/litmus.c295
1 files changed, 295 insertions, 0 deletions
diff --git a/src/litmus.c b/src/litmus.c
new file mode 100644
index 0000000..65ad294
--- /dev/null
+++ b/src/litmus.c
@@ -0,0 +1,295 @@
1#include <stdlib.h>
2#include <stdio.h>
3#include <string.h>
4#include <sys/types.h>
5#include <unistd.h>
6#include <errno.h>
7#include <signal.h>
8#include <sys/mman.h>
9
10
11#include "litmus.h"
12
13
14/* this is missing in newer linux/unistd.h versions */
15
16#define _syscall0(type,name) \
17type name(void) \
18{\
19 return syscall(__NR_##name);\
20}
21
22#define _syscall1(type,name,type1,arg1) \
23type name(type1 arg1) \
24{\
25 return syscall(__NR_##name, arg1);\
26}
27
28
29#define _syscall2(type,name,type1,arg1,type2,arg2) \
30type name(type1 arg1,type2 arg2) \
31{\
32 return syscall(__NR_##name, arg1, arg2);\
33}
34
35
36/* clear the TID in the child */
37#define CLONE_CHILD_CLEARTID 0x00200000
38/* set the TID in the child */
39#define CLONE_CHILD_SETTID 0x01000000
40/* don't let the child run before we have completed setup */
41#define CLONE_STOPPED 0x02000000
42/* litmus clone flag */
43#define CLONE_REALTIME 0x10000000
44
45/* CLONE_REALTIME is necessary because CLONE_STOPPED will put a SIGSTOP in
46 * the pending signal queue. Thus the first thing a newly created task will
47 * do after it is released is to stop, which is not what we want
48 *
49 * CLONE_REALTIME just sets the status to TASK_STOPPED without queueing a
50 * signal.
51 */
52
53
54/* this is essentially a fork with CLONE_STOPPED */
55/* #define CLONE_LITMUS CLONE_STOPPED | CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID */
56#define CLONE_LITMUS CLONE_REALTIME | CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID
57
58/* we need to override libc because it wants to be clever
59 * and rejects our call without presenting it even to the kernel
60 */
61#define __NR_raw_clone 120
62
63
64_syscall2(int, raw_clone, unsigned long, flags, unsigned long, child_stack)
65
66
67const char* get_scheduler_name(spolicy scheduler)
68{
69 const char* name;
70
71 switch (scheduler){
72 case SCHED_LINUX :
73 name = "Linux";
74 break;
75 case SCHED_PFAIR:
76 name = "Pfair";
77 break;
78 case SCHED_PFAIR_STAGGER:
79 name = "Pfair (staggered)";
80 break;
81 case SCHED_PART_EDF:
82 name = "Partioned EDF";
83 break;
84 case SCHED_PART_EEVDF:
85 name = "Partioned EEVDF";
86 break;
87 case SCHED_GLOBAL_EDF:
88 name = "Global EDF";
89 break;
90 case SCHED_EDF_HSB:
91 name = "EDF-HSB";
92 break;
93 case SCHED_GSN_EDF:
94 name = "GSN-EDF";
95 break;
96 case SCHED_PSN_EDF:
97 name = "PSN-EDF";
98 break;
99 default:
100 name = "Unkown";
101 break;
102 }
103 return name;
104}
105
106int create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period) {
107 return __create_rt_task(rt_prog, arg, cpu, wcet, period, RT_CLASS_HARD);
108}
109
110int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period,
111 task_class_t class)
112{
113 int ret;
114 rt_param_t params;
115 int rt_task = raw_clone(CLONE_LITMUS, 0);
116
117 if (rt_task < 0)
118 return rt_task;
119
120 if (rt_task > 0) {
121 /* we are the controller task */
122 params.period = period;
123 params.exec_cost = wcet;
124 params.cpu = cpu;
125 params.cls = class;
126 ret = set_rt_task_param(rt_task, &params);
127 if (ret < 0) {
128 /* we have a problem: we created the task but
129 * for some stupid reason we cannot set the real-time
130 * parameters. We must clean up the stopped task.
131 */
132 kill(rt_task, SIGKILL);
133 /* syscall will have set errno, we don't have to do
134 * anything
135 */
136 return -1;
137 }
138 ret = prepare_rt_task(rt_task);
139 if (ret < 0) {
140 /* same problem as above*/
141 //kill(rt_task, SIGKILL);
142 rt_task = -1;
143 }
144 return rt_task;
145 }
146 else {
147 /* we are the real-time task
148 * launch task and die when it is done
149 */
150
151 exit(rt_prog(arg));
152 }
153}
154
155
156void show_rt_param(rt_param_t* tp)
157{
158 printf("rt params:\n\t"
159 "exec_cost:\t%ld\n\tperiod:\t\t%ld\n\tcpu:\t%d\n",
160 tp->exec_cost, tp->period, tp->cpu);
161}
162
163task_class_t str2class(const char* str)
164{
165 if (!strcmp(str, "hrt"))
166 return RT_CLASS_HARD;
167 else if (!strcmp(str, "srt"))
168 return RT_CLASS_SOFT;
169 else if (!strcmp(str, "be"))
170 return RT_CLASS_BEST_EFFORT;
171 else
172 return -1;
173}
174
175
176
177struct np_flag {
178 #define RT_PREEMPTIVE 0x2050 /* = NP */
179 #define RT_NON_PREEMPTIVE 0x4e50 /* = P */
180 unsigned short preemptivity;
181
182 #define RT_EXIT_NP_REQUESTED 0x5251 /* = RQ */
183 unsigned short request;
184
185 unsigned int ctr;
186};
187
188static struct np_flag np_flag;
189
190int register_np_flag(struct np_flag* flag);
191int signal_exit_np(void);
192
193
194static inline void barrier(void)
195{
196 __asm__ __volatile__("sfence": : :"memory");
197}
198
199void enter_np(void)
200{
201 if (++np_flag.ctr == 1)
202 {
203 np_flag.request = 0;
204 barrier();
205 np_flag.preemptivity = RT_NON_PREEMPTIVE;
206 }
207}
208
209
210void exit_np(void)
211{
212 if (--np_flag.ctr == 0)
213 {
214 np_flag.preemptivity = RT_PREEMPTIVE;
215 barrier();
216 if (np_flag.request == RT_EXIT_NP_REQUESTED)
217 signal_exit_np();
218 }
219}
220
221
222#define check(str) if (ret == -1) {perror(str); fprintf(stderr, \
223 "Could not initialize LITMUS^RT, aborting...\n"); exit(1);}
224
225void init_litmus(void)
226{
227 int ret;
228 np_flag.preemptivity = RT_PREEMPTIVE;
229 np_flag.ctr = 0;
230
231 ret = mlockall(MCL_CURRENT | MCL_FUTURE);
232 check("mlockall");
233 ret = register_np_flag(&np_flag);
234 check("register_np_flag");
235}
236
237
238
239/* Litmus syscalls definitions */
240#define __NR_sched_setpolicy 320
241#define __NR_sched_getpolicy 321
242#define __NR_set_rt_mode 322
243#define __NR_set_rt_task_param 323
244#define __NR_get_rt_task_param 324
245#define __NR_prepare_rt_task 325
246#define __NR_reset_stat 326
247#define __NR_sleep_next_period 327
248#define __NR_scheduler_setup 328
249#define __NR_register_np_flag 329
250#define __NR_signal_exit_np 330
251#define __NR_pi_sema_init 331
252#define __NR_pi_down 332
253#define __NR_pi_up 333
254#define __NR_pi_sema_free 334
255#define __NR_sema_init 335
256#define __NR_down 336
257#define __NR_up 337
258#define __NR_sema_free 338
259#define __NR_srp_sema_init 339
260#define __NR_srp_down 340
261#define __NR_srp_up 341
262#define __NR_reg_task_srp_sem 342
263#define __NR_srp_sema_free 343
264#define __NR_get_job_no 344
265#define __NR_wait_for_job_release 345
266
267
268/* Syscall stub for setting RT mode and scheduling options */
269_syscall1(spolicy, sched_setpolicy, spolicy, arg1);
270_syscall0(spolicy, sched_getpolicy);
271_syscall1(int, set_rt_mode, int, arg1);
272_syscall2(int, set_rt_task_param, pid_t, pid, rt_param_t*, arg1);
273_syscall2(int, get_rt_task_param, pid_t, pid, rt_param_t*, arg1);
274_syscall1(int, prepare_rt_task, pid_t, pid);
275_syscall0(int, reset_stat);
276_syscall0(int, sleep_next_period);
277_syscall2(int, scheduler_setup, int, cmd, void*, param);
278_syscall1(int, register_np_flag, struct np_flag*, flag);
279_syscall0(int, signal_exit_np);
280_syscall0(int, pi_sema_init);
281_syscall1(int, pi_down, pi_sema_id, sem_id);
282_syscall1(int, pi_up, pi_sema_id, sem_id);
283_syscall1(int, pi_sema_free, pi_sema_id, sem_id);
284_syscall0(int, sema_init);
285_syscall1(int, down, sema_id, sem_id);
286_syscall1(int, up, sema_id, sem_id);
287_syscall1(int, sema_free, sema_id, sem_id);
288_syscall0(int, srp_sema_init);
289_syscall1(int, srp_down, srp_sema_id, sem_id);
290_syscall1(int, srp_up, srp_sema_id, sem_id);
291_syscall2(int, reg_task_srp_sem, srp_sema_id, sem_id, pid_t, t_pid);
292_syscall1(int, srp_sema_free, srp_sema_id, sem_id);
293_syscall1(int, get_job_no, unsigned int*, job_no);
294_syscall1(int, wait_for_job_release, unsigned int, job_no);
295