diff options
author | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2007-10-05 12:41:53 -0400 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2007-10-05 12:41:53 -0400 |
commit | 9de8f0850ce4b34a849384d119fc9e5a6f3f8d17 (patch) | |
tree | 236622c3b41231bb74507cd5e3b7f29d61170c43 | |
parent | 7ddb0d79edf783b5cf45af8052195df198788b07 (diff) |
Implement user space adaptive task launching interface.
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | include/adaptive.h | 23 | ||||
-rw-r--r-- | include/litmus.h | 8 | ||||
-rw-r--r-- | src/adaptive.c | 45 | ||||
-rw-r--r-- | src/litmus.c | 60 | ||||
-rw-r--r-- | src/rt_launch.c | 85 |
6 files changed, 191 insertions, 34 deletions
@@ -39,5 +39,5 @@ rt_launch: liblitmus.a litmus.h rt_launch.o | |||
39 | edfhsb: liblitmus.a edf-hsb.o litmus.h edf-hsb.h hrt.o | 39 | edfhsb: liblitmus.a edf-hsb.o litmus.h edf-hsb.h hrt.o |
40 | cc -o edfhsb hrt.o edf-hsb.o ${LIBS} | 40 | cc -o edfhsb hrt.o edf-hsb.o ${LIBS} |
41 | 41 | ||
42 | liblitmus.a: litmus.o litmus.h edf-hsb.o edf-hsb.h | 42 | liblitmus.a: litmus.o adaptive.o adaptive.h litmus.h edf-hsb.o edf-hsb.h |
43 | ${AR} rcs liblitmus.a litmus.o edf-hsb.o | 43 | ${AR} rcs liblitmus.a litmus.o adaptive.o edf-hsb.o |
diff --git a/include/adaptive.h b/include/adaptive.h new file mode 100644 index 0000000..a67c540 --- /dev/null +++ b/include/adaptive.h | |||
@@ -0,0 +1,23 @@ | |||
1 | #ifndef ADAPTIVE_H | ||
2 | #define ADAPTIVE_H | ||
3 | |||
4 | #define MAX_SERVICE_LEVELS 10 | ||
5 | |||
6 | typedef struct { | ||
7 | unsigned long exec_cost; | ||
8 | unsigned long period; | ||
9 | /* fixed point */ | ||
10 | unsigned long utility; | ||
11 | } service_level_t; | ||
12 | |||
13 | int set_service_levels(pid_t pid, | ||
14 | unsigned int nr_levels, | ||
15 | service_level_t* levels); | ||
16 | |||
17 | int get_cur_service_level(void); | ||
18 | |||
19 | int create_adaptive_rt_task(rt_fn_t rt_prog, void *arg, | ||
20 | unsigned int no_levels, service_level_t* levels); | ||
21 | |||
22 | |||
23 | #endif | ||
diff --git a/include/litmus.h b/include/litmus.h index 3595919..01503aa 100644 --- a/include/litmus.h +++ b/include/litmus.h | |||
@@ -8,6 +8,7 @@ | |||
8 | #define CLONE_REALTIME 0x10000000 | 8 | #define CLONE_REALTIME 0x10000000 |
9 | 9 | ||
10 | typedef int (*rt_fn_t)(void*); | 10 | typedef int (*rt_fn_t)(void*); |
11 | typedef int (*rt_setup_fn_t)(int pid, void* arg); | ||
11 | 12 | ||
12 | /* Litmus scheduling policies */ | 13 | /* Litmus scheduling policies */ |
13 | typedef enum { | 14 | typedef enum { |
@@ -99,6 +100,7 @@ void init_litmus(void); | |||
99 | #define exit_litmus() {} | 100 | #define exit_litmus() {} |
100 | 101 | ||
101 | 102 | ||
103 | |||
102 | int create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period); | 104 | int create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period); |
103 | int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, | 105 | int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, |
104 | int period, task_class_t cls); | 106 | int period, task_class_t cls); |
@@ -111,4 +113,10 @@ void exit_np(void); | |||
111 | 113 | ||
112 | int litmus_task_active(); | 114 | int litmus_task_active(); |
113 | 115 | ||
116 | |||
117 | /* low level operations, not intended for API use */ | ||
118 | int fork_rt(void); | ||
119 | int __launch_rt_task(rt_fn_t rt_prog, void *rt_arg, | ||
120 | rt_setup_fn_t setup, void* setup_arg); | ||
121 | |||
114 | #endif | 122 | #endif |
diff --git a/src/adaptive.c b/src/adaptive.c new file mode 100644 index 0000000..ebf662d --- /dev/null +++ b/src/adaptive.c | |||
@@ -0,0 +1,45 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <unistd.h> | ||
3 | |||
4 | #include "litmus.h" | ||
5 | #include "adaptive.h" | ||
6 | |||
7 | #define __NR_set_service_levels 346 | ||
8 | #define __NR_get_cur_service_level 347 | ||
9 | |||
10 | |||
11 | |||
12 | int set_service_levels(pid_t pid, | ||
13 | unsigned int nr_levels, | ||
14 | service_level_t* levels) | ||
15 | { | ||
16 | return syscall(__NR_set_service_levels, pid, nr_levels, levels); | ||
17 | } | ||
18 | |||
19 | |||
20 | int get_cur_service_level(void) | ||
21 | { | ||
22 | return syscall(__NR_get_cur_service_level); | ||
23 | } | ||
24 | |||
25 | |||
26 | struct adaptive_param { | ||
27 | unsigned int no_levels; | ||
28 | service_level_t* levels; | ||
29 | }; | ||
30 | |||
31 | int setup_adaptive(int pid, struct adaptive_param* arg) | ||
32 | { | ||
33 | return set_service_levels(pid, arg->no_levels, arg->levels); | ||
34 | } | ||
35 | |||
36 | int create_adaptive_rt_task(rt_fn_t rt_prog, void *arg, | ||
37 | unsigned int no_levels, service_level_t* levels) | ||
38 | { | ||
39 | struct adaptive_param p; | ||
40 | p.no_levels = no_levels; | ||
41 | p.levels = levels; | ||
42 | return __launch_rt_task(rt_prog, arg, | ||
43 | (rt_setup_fn_t) setup_adaptive, &p); | ||
44 | } | ||
45 | |||
diff --git a/src/litmus.c b/src/litmus.c index 9a2ebea..b39da7f 100644 --- a/src/litmus.c +++ b/src/litmus.c | |||
@@ -63,6 +63,12 @@ type name(type1 arg1,type2 arg2) \ | |||
63 | 63 | ||
64 | _syscall2(int, raw_clone, unsigned long, flags, unsigned long, child_stack) | 64 | _syscall2(int, raw_clone, unsigned long, flags, unsigned long, child_stack) |
65 | 65 | ||
66 | int fork_rt(void) | ||
67 | { | ||
68 | int rt_task = raw_clone(CLONE_LITMUS, 0); | ||
69 | return rt_task; | ||
70 | } | ||
71 | |||
66 | 72 | ||
67 | const char* get_scheduler_name(spolicy scheduler) | 73 | const char* get_scheduler_name(spolicy scheduler) |
68 | { | 74 | { |
@@ -103,27 +109,20 @@ const char* get_scheduler_name(spolicy scheduler) | |||
103 | return name; | 109 | return name; |
104 | } | 110 | } |
105 | 111 | ||
106 | int 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 | 112 | ||
110 | int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period, | 113 | /* common launch routine */ |
111 | task_class_t class) | 114 | int __launch_rt_task(rt_fn_t rt_prog, void *rt_arg, rt_setup_fn_t setup, |
115 | void* setup_arg) | ||
112 | { | 116 | { |
113 | int ret; | 117 | int ret; |
114 | rt_param_t params; | 118 | int rt_task = fork_rt(); |
115 | int rt_task = raw_clone(CLONE_LITMUS, 0); | ||
116 | 119 | ||
117 | if (rt_task < 0) | 120 | if (rt_task < 0) |
118 | return rt_task; | 121 | return rt_task; |
119 | 122 | ||
120 | if (rt_task > 0) { | 123 | if (rt_task > 0) { |
121 | /* we are the controller task */ | 124 | /* we are the controller task */ |
122 | params.period = period; | 125 | ret = setup(rt_task, setup_arg); |
123 | params.exec_cost = wcet; | ||
124 | params.cpu = cpu; | ||
125 | params.cls = class; | ||
126 | ret = set_rt_task_param(rt_task, ¶ms); | ||
127 | if (ret < 0) { | 126 | if (ret < 0) { |
128 | /* we have a problem: we created the task but | 127 | /* we have a problem: we created the task but |
129 | * for some stupid reason we cannot set the real-time | 128 | * for some stupid reason we cannot set the real-time |
@@ -138,7 +137,7 @@ int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period, | |||
138 | ret = prepare_rt_task(rt_task); | 137 | ret = prepare_rt_task(rt_task); |
139 | if (ret < 0) { | 138 | if (ret < 0) { |
140 | /* same problem as above*/ | 139 | /* same problem as above*/ |
141 | //kill(rt_task, SIGKILL); | 140 | kill(rt_task, SIGKILL); |
142 | rt_task = -1; | 141 | rt_task = -1; |
143 | } | 142 | } |
144 | return rt_task; | 143 | return rt_task; |
@@ -148,10 +147,43 @@ int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period, | |||
148 | * launch task and die when it is done | 147 | * launch task and die when it is done |
149 | */ | 148 | */ |
150 | 149 | ||
151 | exit(rt_prog(arg)); | 150 | exit(rt_prog(rt_arg)); |
152 | } | 151 | } |
153 | } | 152 | } |
154 | 153 | ||
154 | struct create_rt_param { | ||
155 | int cpu; | ||
156 | int wcet; | ||
157 | int period; | ||
158 | task_class_t class; | ||
159 | }; | ||
160 | |||
161 | int setup_create_rt(int pid, struct create_rt_param* arg) | ||
162 | { | ||
163 | rt_param_t params; | ||
164 | params.period = arg->period; | ||
165 | params.exec_cost = arg->wcet; | ||
166 | params.cpu = arg->cpu; | ||
167 | params.cls = arg->class; | ||
168 | return set_rt_task_param(pid, ¶ms); | ||
169 | } | ||
170 | |||
171 | int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period, | ||
172 | task_class_t class) | ||
173 | { | ||
174 | struct create_rt_param params; | ||
175 | params.cpu = cpu; | ||
176 | params.period = period; | ||
177 | params.wcet = wcet; | ||
178 | params.class = class; | ||
179 | return __launch_rt_task(rt_prog, arg, | ||
180 | (rt_setup_fn_t) setup_create_rt, ¶ms); | ||
181 | } | ||
182 | |||
183 | int create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period) { | ||
184 | return __create_rt_task(rt_prog, arg, cpu, wcet, period, RT_CLASS_HARD); | ||
185 | } | ||
186 | |||
155 | 187 | ||
156 | void show_rt_param(rt_param_t* tp) | 188 | void show_rt_param(rt_param_t* tp) |
157 | { | 189 | { |
diff --git a/src/rt_launch.c b/src/rt_launch.c index a90bea8..cd98ad3 100644 --- a/src/rt_launch.c +++ b/src/rt_launch.c | |||
@@ -1,8 +1,11 @@ | |||
1 | #include <stdio.h> | 1 | #include <stdio.h> |
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <string.h> | ||
3 | #include <unistd.h> | 4 | #include <unistd.h> |
5 | #include <limits.h> | ||
4 | 6 | ||
5 | #include "litmus.h" | 7 | #include "litmus.h" |
8 | #include "adaptive.h" | ||
6 | 9 | ||
7 | typedef struct { | 10 | typedef struct { |
8 | char * exec_path; | 11 | char * exec_path; |
@@ -20,12 +23,38 @@ int launch(void *task_info_p) { | |||
20 | 23 | ||
21 | void usage(char *error) { | 24 | void usage(char *error) { |
22 | fprintf(stderr, "%s\nUsage: launch_rt [-c {hrt|srt|be}] [-p <cpu>]" | 25 | fprintf(stderr, "%s\nUsage: launch_rt [-c {hrt|srt|be}] [-p <cpu>]" |
23 | "<wcet> <period> program arg1 arg2 ...\n", | 26 | "{<wcet> <period>|{-a wcet/period/utility}+}" |
27 | " program arg1 arg2 ...\n", | ||
24 | error); | 28 | error); |
25 | exit(1); | 29 | exit(1); |
26 | } | 30 | } |
27 | 31 | ||
28 | #define OPTSTR "p:c:" | 32 | /* argument format should be wcet/period/utility */ |
33 | static int parse_service_level(service_level_t* level, char* str) | ||
34 | { | ||
35 | char *wcet, *period, *utility; | ||
36 | double u; | ||
37 | wcet = strtok(str, "/"); | ||
38 | period = strtok(NULL, "/"); | ||
39 | utility = strtok(NULL, "/"); | ||
40 | str = strtok(NULL, "/"); | ||
41 | |||
42 | if (str || !utility || !period || !wcet) | ||
43 | return 0; | ||
44 | |||
45 | level->exec_cost = atol(wcet); | ||
46 | level->period = atol(period); | ||
47 | u = atof(utility); | ||
48 | |||
49 | if (level->exec_cost == 0 || level->period < level->exec_cost || | ||
50 | u <= 0.0 || u > 1.0) | ||
51 | return 0; | ||
52 | |||
53 | level->utility = (unsigned long) ULONG_MAX * u; | ||
54 | return 1; | ||
55 | } | ||
56 | |||
57 | #define OPTSTR "p:c:a:" | ||
29 | 58 | ||
30 | int main(int argc, char** argv) | 59 | int main(int argc, char** argv) |
31 | { | 60 | { |
@@ -36,9 +65,20 @@ int main(int argc, char** argv) | |||
36 | int opt; | 65 | int opt; |
37 | startup_info_t info; | 66 | startup_info_t info; |
38 | task_class_t class = RT_CLASS_HARD; | 67 | task_class_t class = RT_CLASS_HARD; |
68 | |||
69 | int adaptive = 0; | ||
70 | unsigned int level = 0; | ||
71 | service_level_t slevel[MAX_SERVICE_LEVELS]; | ||
39 | 72 | ||
40 | while ((opt = getopt(argc, argv, OPTSTR)) != -1) { | 73 | while ((opt = getopt(argc, argv, OPTSTR)) != -1) { |
41 | switch (opt) { | 74 | switch (opt) { |
75 | case 'a': | ||
76 | adaptive = 1; | ||
77 | if (level == MAX_SERVICE_LEVELS) | ||
78 | usage("Too many service levels."); | ||
79 | if (!parse_service_level(slevel + level++, optarg)) | ||
80 | usage("Bad service level."); | ||
81 | break; | ||
42 | case 'p': | 82 | case 'p': |
43 | cpu = atoi(optarg); | 83 | cpu = atoi(optarg); |
44 | break; | 84 | break; |
@@ -58,23 +98,32 @@ int main(int argc, char** argv) | |||
58 | } | 98 | } |
59 | } | 99 | } |
60 | 100 | ||
61 | if (argc - optind < 3) | 101 | if (!adaptive) { |
62 | { | 102 | if (argc - optind < 3) |
63 | printf("argc: %d optind: %d\n", argc, optind); | 103 | usage("Arguments missing."); |
64 | usage("Arguments missing."); | 104 | wcet = atoi(argv[optind + 0]); |
65 | } | 105 | period = atoi(argv[optind + 1]); |
66 | wcet = atoi(argv[optind + 0]); | 106 | if (wcet <= 0) |
67 | period = atoi(argv[optind + 1]); | 107 | usage("The worst-case execution time must be a " |
68 | if (wcet <= 0) | 108 | "positive number."); |
69 | usage("The worst-case execution time must be a positive number."); | 109 | if (period <= 0) |
70 | if (period <= 0) | 110 | usage("The period must be a positive number."); |
71 | usage("The period must be a positive number."); | 111 | if (wcet > period) { |
72 | if (wcet > period) { | 112 | usage("The worst-case execution time must not " |
73 | usage("The worst-case execution time must not exceed the period."); | 113 | "exceed the period."); |
114 | } | ||
115 | info.exec_path = argv[optind + 2]; | ||
116 | info.argv = argv + optind + 2; | ||
117 | ret = __create_rt_task(launch, &info, cpu, wcet, period, class); | ||
118 | } else { | ||
119 | if (argc == optind) | ||
120 | usage("Arguments missing."); | ||
121 | info.exec_path = argv[optind]; | ||
122 | info.argv = argv + optind; | ||
123 | ret = create_adaptive_rt_task(launch, &info, level, slevel); | ||
74 | } | 124 | } |
75 | info.exec_path = argv[optind + 2]; | 125 | |
76 | info.argv = argv + optind + 2; | 126 | |
77 | ret = __create_rt_task(launch, &info, cpu, wcet, period, class); | ||
78 | if (ret < 0) { | 127 | if (ret < 0) { |
79 | perror("Could not create rt child process"); | 128 | perror("Could not create rt child process"); |
80 | return 2; | 129 | return 2; |