diff options
author | Bjoern B. Brandenburg <bbb@jupiter-cs.cs.unc.edu> | 2007-02-05 18:31:20 -0500 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@jupiter-cs.cs.unc.edu> | 2007-02-05 18:31:20 -0500 |
commit | b32b21bd57b21b249447e2944c4473e0d196bb4f (patch) | |
tree | fea9e8712fbc97f30003065074a1ff180f3e1de4 /litmus.c |
liblitmus essential tools
liblitmus should consist only of the litmus library and the essential
tools.
Diffstat (limited to 'litmus.c')
-rw-r--r-- | litmus.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/litmus.c b/litmus.c new file mode 100644 index 0000000..6f4aa18 --- /dev/null +++ b/litmus.c | |||
@@ -0,0 +1,188 @@ | |||
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 | |||
9 | #include "litmus.h" | ||
10 | |||
11 | /* this is missing in newer linux/unistd.h versions */ | ||
12 | |||
13 | #define _syscall0(type,name) \ | ||
14 | type name(void) \ | ||
15 | {\ | ||
16 | return syscall(__NR_##name);\ | ||
17 | } | ||
18 | |||
19 | #define _syscall1(type,name,type1,arg1) \ | ||
20 | type name(type1 arg1) \ | ||
21 | {\ | ||
22 | return syscall(__NR_##name, arg1);\ | ||
23 | } | ||
24 | |||
25 | |||
26 | #define _syscall2(type,name,type1,arg1,type2,arg2) \ | ||
27 | type name(type1 arg1,type2 arg2) \ | ||
28 | {\ | ||
29 | return syscall(__NR_##name, arg1, arg2);\ | ||
30 | } | ||
31 | |||
32 | |||
33 | /* clear the TID in the child */ | ||
34 | #define CLONE_CHILD_CLEARTID 0x00200000 | ||
35 | /* set the TID in the child */ | ||
36 | #define CLONE_CHILD_SETTID 0x01000000 | ||
37 | /* don't let the child run before we have completed setup */ | ||
38 | #define CLONE_STOPPED 0x02000000 | ||
39 | /* litmus clone flag */ | ||
40 | #define CLONE_REALTIME 0x10000000 | ||
41 | |||
42 | /* CLONE_REALTIME is necessary because CLONE_STOPPED will put a SIGSTOP in | ||
43 | * the pending signal queue. Thus the first thing a newly created task will | ||
44 | * do after it is released is to stop, which is not what we want | ||
45 | * | ||
46 | * CLONE_REALTIME just sets the status to TASK_STOPPED without queueing a | ||
47 | * signal. | ||
48 | */ | ||
49 | |||
50 | |||
51 | /* this is essentially a fork with CLONE_STOPPED */ | ||
52 | /* #define CLONE_LITMUS CLONE_STOPPED | CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID */ | ||
53 | #define CLONE_LITMUS CLONE_REALTIME | CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | ||
54 | |||
55 | /* we need to override libc because it wants to be clever | ||
56 | * and rejects our call without presenting it even to the kernel | ||
57 | */ | ||
58 | #define __NR_raw_clone 120 | ||
59 | |||
60 | |||
61 | _syscall2(int, raw_clone, unsigned long, flags, unsigned long, child_stack) | ||
62 | |||
63 | |||
64 | const char* get_scheduler_name(spolicy scheduler) | ||
65 | { | ||
66 | const char* name; | ||
67 | |||
68 | switch (scheduler){ | ||
69 | case SCHED_LINUX : | ||
70 | name = "Linux"; | ||
71 | break; | ||
72 | case SCHED_PFAIR: | ||
73 | name = "Pfair"; | ||
74 | break; | ||
75 | case SCHED_PFAIR_STAGGER: | ||
76 | name = "Pfair (staggered)"; | ||
77 | break; | ||
78 | case SCHED_PART_EDF: | ||
79 | name = "Partioned EDF"; | ||
80 | break; | ||
81 | case SCHED_PART_EEVDF: | ||
82 | name = "Partioned EEVDF"; | ||
83 | break; | ||
84 | case SCHED_GLOBAL_EDF: | ||
85 | name = "Global EDF"; | ||
86 | break; | ||
87 | case SCHED_EDF_HSB: | ||
88 | name = "EDF-HSB"; | ||
89 | break; | ||
90 | default: | ||
91 | name = "Unkown"; | ||
92 | break; | ||
93 | } | ||
94 | return name; | ||
95 | } | ||
96 | |||
97 | int create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period) { | ||
98 | return __create_rt_task(rt_prog, arg, cpu, wcet, period, RT_CLASS_HARD); | ||
99 | } | ||
100 | |||
101 | int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period, | ||
102 | task_class_t class) | ||
103 | { | ||
104 | int ret; | ||
105 | rt_param_t params; | ||
106 | int rt_task = raw_clone(CLONE_LITMUS, 0); | ||
107 | |||
108 | if (rt_task < 0) | ||
109 | return rt_task; | ||
110 | |||
111 | if (rt_task > 0) { | ||
112 | /* we are the controller task */ | ||
113 | params.period = period; | ||
114 | params.exec_cost = wcet; | ||
115 | params.cpu = cpu; | ||
116 | params.cls = class; | ||
117 | ret = set_rt_task_param(rt_task, ¶ms); | ||
118 | if (ret < 0) { | ||
119 | /* we have a problem: we created the task but | ||
120 | * for some stupid reason we cannot set the real-time | ||
121 | * parameters. We must clean up the stopped task. | ||
122 | */ | ||
123 | kill(rt_task, SIGKILL); | ||
124 | /* syscall will have set errno, we don't have to do | ||
125 | * anything | ||
126 | */ | ||
127 | return -1; | ||
128 | } | ||
129 | ret = prepare_rt_task(rt_task); | ||
130 | if (ret < 0) { | ||
131 | /* same problem as above*/ | ||
132 | //kill(rt_task, SIGKILL); | ||
133 | rt_task = -1; | ||
134 | } | ||
135 | return rt_task; | ||
136 | } | ||
137 | else { | ||
138 | /* we are the real-time task | ||
139 | * launch task and die when it is done | ||
140 | */ | ||
141 | |||
142 | exit(rt_prog(arg)); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | |||
147 | void show_rt_param(rt_param_t* tp) | ||
148 | { | ||
149 | printf("rt params:\n\t" | ||
150 | "exec_cost:\t%ld\n\tperiod:\t\t%ld\n\tcpu:\t%d\n", | ||
151 | tp->exec_cost, tp->period, tp->cpu); | ||
152 | } | ||
153 | |||
154 | task_class_t str2class(const char* str) | ||
155 | { | ||
156 | if (!strcmp(str, "hrt")) | ||
157 | return RT_CLASS_HARD; | ||
158 | else if (!strcmp(str, "srt")) | ||
159 | return RT_CLASS_SOFT; | ||
160 | else if (!strcmp(str, "be")) | ||
161 | return RT_CLASS_BEST_EFFORT; | ||
162 | else | ||
163 | return -1; | ||
164 | } | ||
165 | |||
166 | |||
167 | /* Litmus syscalls definitions */ | ||
168 | #define __NR_sched_setpolicy 320 | ||
169 | #define __NR_sched_getpolicy 321 | ||
170 | #define __NR_set_rt_mode 322 | ||
171 | #define __NR_set_rt_task_param 323 | ||
172 | #define __NR_get_rt_task_param 324 | ||
173 | #define __NR_prepare_rt_task 325 | ||
174 | #define __NR_reset_stat 326 | ||
175 | #define __NR_sleep_next_period 327 | ||
176 | #define __NR_scheduler_setup 328 | ||
177 | |||
178 | |||
179 | /* Syscall stub for setting RT mode and scheduling options */ | ||
180 | _syscall1(spolicy, sched_setpolicy, spolicy, arg1); | ||
181 | _syscall0(spolicy, sched_getpolicy); | ||
182 | _syscall1(int, set_rt_mode, int, arg1); | ||
183 | _syscall2(int, set_rt_task_param, pid_t, pid, rt_param_t*, arg1); | ||
184 | _syscall2(int, get_rt_task_param, pid_t, pid, rt_param_t*, arg1); | ||
185 | _syscall1(int, prepare_rt_task, pid_t, pid); | ||
186 | _syscall0(int, reset_stat); | ||
187 | _syscall0(int, sleep_next_period); | ||
188 | _syscall2(int, scheduler_setup, int, cmd, void*, param); | ||