aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@jupiter-cs.cs.unc.edu>2007-02-05 18:31:20 -0500
committerBjoern B. Brandenburg <bbb@jupiter-cs.cs.unc.edu>2007-02-05 18:31:20 -0500
commitb32b21bd57b21b249447e2944c4473e0d196bb4f (patch)
treefea9e8712fbc97f30003065074a1ff180f3e1de4
liblitmus essential tools
liblitmus should consist only of the litmus library and the essential tools.
-rw-r--r--Makefile28
-rw-r--r--edf-hsb.c48
-rw-r--r--edf-hsb.h10
-rw-r--r--hrt.c78
-rw-r--r--iotest.c74
-rw-r--r--litmus.c188
-rw-r--r--litmus.h80
-rw-r--r--rt_launch.c83
-rw-r--r--run.c7
-rw-r--r--set_rt_mode.c22
-rw-r--r--show_scheduler.c11
-rw-r--r--timeout.c36
12 files changed, 665 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5157fdf
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,28 @@
1CFLAGS=-Wall -g
2CPPFLAGS=-Wall -g
3
4
5all: showsched iotest set_rt_mode run timeout rt_launch edfhsb
6
7
8iotest: iotest.o litmus.h litmus.o
9 cc -static -o iotest litmus.o iotest.o
10
11run: run.o
12 cc -o run run.o
13
14set_rt_mode: litmus.o set_rt_mode.o
15 cc -o set_rt_mode litmus.o set_rt_mode.o
16
17showsched: show_scheduler.o litmus.o litmus.h
18 cc -o showsched show_scheduler.o litmus.o
19
20timeout: litmus.o timeout.o litmus.h
21 cc -static -o timeout litmus.o timeout.o
22
23rt_launch: litmus.o litmus.h rt_launch.o
24 cc -static -o rt_launch litmus.o rt_launch.o
25
26edfhsb: litmus.o edf-hsb.o litmus.h edf-hsb.h hrt.o
27 cc -o edfhsb hrt.o litmus.o edf-hsb.o
28
diff --git a/edf-hsb.c b/edf-hsb.c
new file mode 100644
index 0000000..9ace2ca
--- /dev/null
+++ b/edf-hsb.c
@@ -0,0 +1,48 @@
1#include "litmus.h"
2#include "edf-hsb.h"
3
4
5typedef enum {
6 EDF_HSB_SET_HRT,
7 EDF_HSB_GET_HRT,
8 EDF_HSB_CREATE_BE
9} edf_hsb_setup_cmds_t;
10
11typedef struct {
12 int cpu;
13 unsigned int wcet;
14 unsigned int period;
15} setup_hrt_param_t;
16
17typedef struct {
18 unsigned int wcet;
19 unsigned int period;
20} create_be_param_t;
21
22int set_hrt(int cpu, unsigned int wcet, unsigned int period)
23{
24 setup_hrt_param_t param;
25 param.cpu = cpu;
26 param.wcet = wcet;
27 param.period = period;
28 return scheduler_setup(EDF_HSB_SET_HRT, &param);
29}
30
31int get_hrt(int cpu, unsigned int *wcet, unsigned int *period)
32{
33 setup_hrt_param_t param;
34 int ret;
35 param.cpu = cpu;
36 ret = scheduler_setup(EDF_HSB_GET_HRT, &param);
37 *wcet = param.wcet;
38 *period = param.period;
39 return ret;
40}
41
42int create_be(unsigned int wcet, unsigned int period)
43{
44 create_be_param_t param;
45 param.wcet = wcet;
46 param.period = period;
47 return scheduler_setup(EDF_HSB_CREATE_BE, &param);
48}
diff --git a/edf-hsb.h b/edf-hsb.h
new file mode 100644
index 0000000..0ac3d4f
--- /dev/null
+++ b/edf-hsb.h
@@ -0,0 +1,10 @@
1#ifndef EDF_HSB_H
2#define EDF_HSB_H
3
4
5int set_hrt(int cpu, unsigned int wcet, unsigned int period);
6int get_hrt(int cpu, unsigned int *wcet, unsigned int *period);
7int create_be(unsigned int wcet, unsigned int period);
8
9
10#endif
diff --git a/hrt.c b/hrt.c
new file mode 100644
index 0000000..224293c
--- /dev/null
+++ b/hrt.c
@@ -0,0 +1,78 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include "edf-hsb.h"
6
7
8void usage(char *name)
9{
10 fprintf(stderr,
11 "EDF-HSB server setup utility\n"
12 "Usage: %s hrt show <#cpu>\n"
13 " %s hrt set <#cpu> <wcet> <period>\n"
14 " %s be create <wcet> <period>\n",
15 name, name, name);
16 exit(1);
17}
18
19
20int hrt(int argc, char** argv)
21{
22 int wcet, period, cpu;
23
24 if (argc == 2 && !strcmp(argv[0], "show")) {
25 cpu = atoi(argv[1]);
26 if (!get_hrt(cpu, &wcet, &period))
27 printf("HRT/%d = (%d, %d)\n", cpu, wcet, period);
28 else
29 perror("cannot read HRT settings");
30 } else if (argc == 4 && !strcmp(argv[0], "set")) {
31 cpu = atoi(argv[1]);
32 wcet = atoi(argv[2]);
33 period = atoi(argv[3]);
34 printf("Setting HRT/%d to (%d, %d)", cpu, wcet, period);
35 if (!set_hrt(cpu, wcet, period))
36 printf(" OK.\n");
37 else {
38 printf("\n");
39 perror("cannot write HRT settings");
40 }
41 } else
42 return 1;
43
44 return 0;
45}
46
47int be(int argc, char** argv)
48{
49 int wcet, period;
50 if (argc == 3 && !strcmp(argv[0], "create")) {
51 wcet = atoi(argv[1]);
52 period = atoi(argv[2]);
53 printf("Creating BE with (%d, %d)", wcet, period);
54 if (!create_be(wcet, period))
55 printf(" OK.\n");
56 else {
57 printf("\n");
58 perror("cannot create BE server");
59 }
60 return 0;
61 }
62 else
63 return 1;
64}
65
66int main(int argc, char** argv)
67{
68 int ret = 1;
69 if (argc > 1) {
70 if (!strcmp(argv[1], "hrt"))
71 ret = hrt(argc - 2, argv + 2);
72 else if (!strcmp(argv[1], "be"))
73 ret = be(argc - 2, argv + 2);
74 }
75 if (ret)
76 usage(argv[0]);
77 return ret;
78}
diff --git a/iotest.c b/iotest.c
new file mode 100644
index 0000000..ac07e74
--- /dev/null
+++ b/iotest.c
@@ -0,0 +1,74 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <signal.h>
4#include <unistd.h>
5#include <sys/time.h>
6#include <sys/wait.h>
7
8#include "litmus.h"
9
10#define US_PER_MS 1000
11
12int iotest(void *nil) {
13 int id = getpid();
14 FILE* file;
15 char str[255];
16 unsigned long last = 0;
17 struct timeval time;
18
19 printf("I'am real time task %d doing IO!\n", id);
20 snprintf(str, sizeof(str), "rt-io-%d.txt", id);
21 file = fopen(str, "w");
22 if (!file) {
23 perror("could not open file for output");
24 exit(1);
25 }
26 while (1) {
27 gettimeofday(&time, NULL);
28 if (time.tv_usec - last > US_PER_MS) {
29 fprintf(file, "ran at %lus %lums\n", time.tv_sec, time.tv_usec / US_PER_MS);
30 last = time.tv_usec;
31 }
32 fflush(file);
33 }
34 return id;
35}
36
37#define NUMTASKS 4
38
39int main(int argc, char** argv)
40{
41 int rt_task[NUMTASKS];
42 int i;
43 int ret, pid;
44
45 for (i = 0; i < NUMTASKS; i++) {
46 /* func arg cpu wcet period */
47 rt_task[i] = create_rt_task(iotest, NULL, 0, 25, 100);
48 if (rt_task[i] < 0) {
49 perror("Could not create rt child process");
50 }
51 }
52
53 sync();
54 sync();
55
56 printf(":: Starting real-time mode.\n");
57 set_rt_mode(MODE_RT_RUN);
58
59 printf(":: Sleeping...\n");
60 sleep(120);
61
62 printf("Killing real-time tasks.\n");
63 for (i = 0; i < NUMTASKS; i++) {
64 printf(":: sending SIGKILL to %d\n", rt_task[i]);
65 kill(rt_task[i], SIGKILL);
66 }
67 for (i = 0; i < NUMTASKS; i++) {
68 pid = wait(&ret);
69 printf(":: %d exited with status %d\n", pid, ret);
70 }
71 printf(":: Leaving real-time mode.\n");
72 set_rt_mode(MODE_NON_RT);
73 return 0;
74}
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) \
14type name(void) \
15{\
16 return syscall(__NR_##name);\
17}
18
19#define _syscall1(type,name,type1,arg1) \
20type name(type1 arg1) \
21{\
22 return syscall(__NR_##name, arg1);\
23}
24
25
26#define _syscall2(type,name,type1,arg1,type2,arg2) \
27type 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
64const 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
97int 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
101int __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, &params);
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
147void 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
154task_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);
diff --git a/litmus.h b/litmus.h
new file mode 100644
index 0000000..8b92383
--- /dev/null
+++ b/litmus.h
@@ -0,0 +1,80 @@
1#ifndef LITMUS_H
2#define LITMUS_H
3
4#include <sys/types.h>
5
6/* This flag is needed to start new RT tasks in STOPPED state */
7/* Task is going to run in realtime mode */
8#define CLONE_REALTIME 0x10000000
9
10typedef int (*rt_fn_t)(void*);
11
12/* Litmus scheduling policies */
13typedef enum {
14 SCHED_LINUX = 0,
15 SCHED_PFAIR = 1,
16 SCHED_PFAIR_STAGGER = 2,
17 SCHED_PART_EDF = 3,
18 SCHED_PART_EEVDF = 4,
19 SCHED_GLOBAL_EDF = 5,
20 SCHED_PFAIR_DESYNC = 6,
21 SCHED_GLOBAL_EDF_NP = 7,
22 SCHED_CUSTOM = 8,
23 SCHED_EDF_HSB = 9,
24} spolicy;
25
26/* different types of clients */
27typedef enum {
28 RT_CLASS_HARD,
29 RT_CLASS_SOFT,
30 RT_CLASS_BEST_EFFORT
31} task_class_t;
32
33/* Task RT params for schedulers */
34/* RT task parameters for scheduling extensions
35* These parameters are inherited during clone and therefore must
36* be explicitly set up before the task set is launched.
37*/
38typedef struct rt_param {
39 /* Execution cost */
40 unsigned long exec_cost;
41 /* Period */
42 unsigned long period;
43 /* Partition */
44 unsigned int cpu;
45 /* type of task */
46 task_class_t cls;
47} rt_param_t;
48
49#define set_param(t,p,e) do{\
50 (t).is_realtime=1;\
51 (t).exec_cost=(e);\
52 (t).period=(p);\
53 }while(0);
54
55/* scheduler modes */
56#define MODE_NON_RT 0
57#define MODE_RT_RUN 1
58
59spolicy sched_setpolicy(spolicy policy);
60spolicy sched_getpolicy(void);
61int set_rt_mode(int mode);
62int set_rt_task_param(pid_t pid, rt_param_t* param);
63int get_rt_task_param(pid_t pid, rt_param_t* param);
64int prepare_rt_task(pid_t pid);
65int tear_down_task(pid_t pid, int sig);
66int reset_stat(void);
67int sleep_next_period(void);
68int scheduler_setup(int cmd, void* param);
69
70
71/* library functions */
72int create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period);
73int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet,
74 int period, task_class_t cls);
75const char* get_scheduler_name(spolicy scheduler);
76void show_rt_param(rt_param_t* tp);
77task_class_t str2class(const char* str);
78
79
80#endif
diff --git a/rt_launch.c b/rt_launch.c
new file mode 100644
index 0000000..31e6447
--- /dev/null
+++ b/rt_launch.c
@@ -0,0 +1,83 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4
5#include "litmus.h"
6
7typedef struct {
8 char * exec_path;
9 char ** argv;
10} startup_info_t;
11
12
13int launch(void *task_info_p) {
14 startup_info_t *info = (startup_info_t*) task_info_p;
15 int ret;
16 ret = execv(info->exec_path, info->argv);
17 perror("execv failed");
18 return ret;
19}
20
21void usage(char *error) {
22 fprintf(stderr, "%s\nUsage: launch_rt [-c {hrt|srt|be}] [-p <cpu>]"
23 "<wcet> <period> program arg1 arg2 ...\n",
24 error);
25 exit(1);
26}
27
28#define OPTSTR "p:c:"
29
30int main(int argc, char** argv)
31{
32 int ret;
33 int wcet;
34 int period;
35 int cpu = 0;
36 int opt;
37 startup_info_t info;
38 task_class_t class = RT_CLASS_HARD;
39
40 while ((opt = getopt(argc, argv, OPTSTR)) != -1) {
41 switch (opt) {
42 case 'p':
43 cpu = atoi(optarg);
44 break;
45 case 'c':
46 class = str2class(optarg);
47 if (class == -1)
48 usage("Unknown task class.");
49 break;
50
51 case ':':
52 usage("Argument missing.");
53 break;
54 case '?':
55 default:
56 usage("Unknown flag.");
57 break;
58 }
59 }
60
61 if (argc - optind < 3)
62 {
63 printf("argc: %d optind: %d\n", argc, optind);
64 usage("Arguments missing.");
65 }
66 wcet = atoi(argv[optind + 0]);
67 period = atoi(argv[optind + 1]);
68 if (wcet <= 0)
69 usage("The worst-case execution time must be a positive number.");
70 if (period <= 0)
71 usage("The period must be a positive number.");
72 if (wcet > period) {
73 usage("The worst-case execution time must not exceed the period.");
74 }
75 info.exec_path = argv[optind + 2];
76 info.argv = argv + optind + 2;
77 ret = __create_rt_task(launch, &info, cpu, wcet, period, class);
78 if (ret < 0) {
79 perror("Could not create rt child process");
80 }
81
82 return 0;
83}
diff --git a/run.c b/run.c
new file mode 100644
index 0000000..b823efb
--- /dev/null
+++ b/run.c
@@ -0,0 +1,7 @@
1
2
3int main(int argc, char** argv)
4{
5 while (1);
6 return 0;
7}
diff --git a/set_rt_mode.c b/set_rt_mode.c
new file mode 100644
index 0000000..5936d7d
--- /dev/null
+++ b/set_rt_mode.c
@@ -0,0 +1,22 @@
1#include <stdio.h>
2#include <strings.h>
3#include <stdlib.h>
4#include "litmus.h"
5
6
7int main(int argc, char** argv)
8{
9 if (argc == 2) {
10 if (!strcmp(argv[1], "on")) {
11 printf("Enabling real-time mode.\n");
12 set_rt_mode(MODE_RT_RUN);
13 exit(0);
14 } else if (!strcmp(argv[1], "off")) {
15 printf("Disabling real-time mode.\n");
16 set_rt_mode(MODE_NON_RT);
17 exit(0);
18 }
19 }
20 printf("Usage: %s {on|off}\n", argv[0]);
21 return 1;
22}
diff --git a/show_scheduler.c b/show_scheduler.c
new file mode 100644
index 0000000..9bd4072
--- /dev/null
+++ b/show_scheduler.c
@@ -0,0 +1,11 @@
1#include <sys/types.h>
2#include <stdio.h>
3
4#include "litmus.h"
5
6int main(int argc, char** argv) {
7 spolicy scheduler = sched_getpolicy();
8 printf("Current scheduler: %s (%d)\n", get_scheduler_name(scheduler),
9 scheduler);
10 return 0;
11}
diff --git a/timeout.c b/timeout.c
new file mode 100644
index 0000000..ba513f9
--- /dev/null
+++ b/timeout.c
@@ -0,0 +1,36 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4
5#include "litmus.h"
6
7int main(int argc, char** argv)
8{
9 int timeout;
10 rt_param_t my_param;
11
12 if (argc != 2)
13 {
14 printf("Usage: %s <timeout in seconds>\n", argv[0]);
15 exit(1);
16 }
17 timeout = atoi(argv[1]);
18 if (timeout <= 0) {
19 printf("Timeout must be a positive number.\n");
20 exit(1);
21 }
22
23 /* printf("This is the kill real-time mode task.\n"
24 "Expected end of real %u seconds.\n", timeout);
25 */
26 /* get_rt_task_param(getpid(), &my_param);
27 show_rt_param(&my_param);
28 */
29
30 sleep(timeout);
31
32
33 set_rt_mode(MODE_NON_RT);
34 printf("End of real-time mode.\n");
35 return 0;
36}