diff options
-rw-r--r-- | bin/rt_launch.c | 172 | ||||
-rw-r--r-- | include/internal.h | 5 | ||||
-rw-r--r-- | include/litmus.h | 29 | ||||
-rw-r--r-- | src/task.c | 58 |
4 files changed, 112 insertions, 152 deletions
diff --git a/bin/rt_launch.c b/bin/rt_launch.c index 5e29893..c468b68 100644 --- a/bin/rt_launch.c +++ b/bin/rt_launch.c | |||
@@ -8,64 +8,63 @@ | |||
8 | #include "litmus.h" | 8 | #include "litmus.h" |
9 | #include "common.h" | 9 | #include "common.h" |
10 | 10 | ||
11 | typedef struct { | 11 | const char *usage_msg = |
12 | int wait; | 12 | "Usage: rt_launch OPTIONS wcet period program [arg1 arg2 ...]\n" |
13 | char * exec_path; | 13 | " -w wait for synchronous release\n" |
14 | char ** argv; | 14 | " -v verbose (prints PID)\n" |
15 | } startup_info_t; | 15 | " -p CPU physical partition or cluster to assign to\n" |
16 | 16 | " -r VCPU virtual CPU to attach to (irrelevant to most plugins)\n" | |
17 | 17 | " -d DEADLINE relative deadline, implicit by default (in ms)\n" | |
18 | int launch(void *task_info_p) { | 18 | " -o OFFSET offset (also known as phase), zero by default (in ms)\n" |
19 | startup_info_t *info = (startup_info_t*) task_info_p; | 19 | " -q PRIORITY priority to use (ignored by EDF plugins, highest=1, lowest=511)\n" |
20 | int ret; | 20 | " -c be|srt|hrt task class (best-effort, soft real-time, hard real-time)\n" |
21 | if (info->wait) { | 21 | " -e turn off budget enforcement (DANGEROUS: can result in lockup)\n" |
22 | ret = wait_for_ts_release(); | 22 | " wcet, period reservation parameters (in ms)\n" |
23 | if (ret != 0) | 23 | " program path to the binary to be launched\n" |
24 | perror("wait_for_ts_release()"); | 24 | "\n"; |
25 | } | ||
26 | ret = execvp(info->exec_path, info->argv); | ||
27 | perror("execv failed"); | ||
28 | return ret; | ||
29 | } | ||
30 | 25 | ||
31 | void usage(char *error) { | 26 | void usage(char *error) { |
32 | fprintf(stderr, "%s\nUsage: rt_launch [-w][-v][-p partition/cluster [-z cluster size]][-q prio][-c hrt | srt | be] wcet period program [arg1 arg2 ...]\n" | 27 | fprintf(stderr, "%s\n%s", error, usage_msg); |
33 | "\t-w\tSynchronous release\n" | ||
34 | "\t-v\tVerbose\n" | ||
35 | "\t-p\tpartition or cluster\n" | ||
36 | "\t-z\tsize of cluster (default = 1 for partitioned)\n" | ||
37 | "\t-c\tClass\n" | ||
38 | "\twcet, period in ms\n" | ||
39 | "\tprogram to be launched\n", | ||
40 | error); | ||
41 | exit(1); | 28 | exit(1); |
42 | } | 29 | } |
43 | 30 | ||
31 | #define OPTSTR "wp:q:c:er:b:o:d:vh" | ||
44 | 32 | ||
45 | #define OPTSTR "p:c:vwq:" | 33 | int main(int argc, char** argv) |
46 | |||
47 | int main(int argc, char** argv) | ||
48 | { | 34 | { |
49 | int ret; | 35 | int ret, opt; |
50 | lt_t wcet; | 36 | lt_t wcet; |
51 | lt_t period; | 37 | lt_t period; |
52 | int migrate = 0; | 38 | lt_t offset; |
53 | int cluster = 0; | 39 | lt_t deadline; |
54 | int opt; | 40 | double wcet_ms, period_ms, offset_ms, deadline_ms; |
55 | int verbose = 0; | 41 | unsigned int priority; |
56 | int wait = 0; | 42 | int migrate; |
57 | startup_info_t info; | 43 | int cluster; |
58 | task_class_t class = RT_CLASS_HARD; | 44 | int reservation; |
59 | unsigned int priority = LITMUS_LOWEST_PRIORITY; | 45 | int wait; |
46 | int want_enforcement; | ||
47 | int verbose; | ||
48 | task_class_t class; | ||
49 | struct rt_task param; | ||
50 | |||
51 | /* Reasonable defaults */ | ||
52 | verbose = 0; | ||
53 | offset_ms = 0; | ||
54 | deadline_ms = 0; | ||
55 | priority = LITMUS_LOWEST_PRIORITY; | ||
56 | want_enforcement = 1; /* safety: default to enforcement */ | ||
57 | wait = 0; /* don't wait for task system release */ | ||
58 | class = RT_CLASS_SOFT; /* ignored by most plugins */ | ||
59 | migrate = 0; /* assume global unless -p is specified */ | ||
60 | cluster = -1; /* where to migrate to, invalid by default */ | ||
61 | reservation = -1; /* set if task should attach to virtual CPU */ | ||
60 | 62 | ||
61 | while ((opt = getopt(argc, argv, OPTSTR)) != -1) { | 63 | while ((opt = getopt(argc, argv, OPTSTR)) != -1) { |
62 | switch (opt) { | 64 | switch (opt) { |
63 | case 'w': | 65 | case 'w': |
64 | wait = 1; | 66 | wait = 1; |
65 | break; | 67 | break; |
66 | case 'v': | ||
67 | verbose = 1; | ||
68 | break; | ||
69 | case 'p': | 68 | case 'p': |
70 | cluster = atoi(optarg); | 69 | cluster = atoi(optarg); |
71 | migrate = 1; | 70 | migrate = 1; |
@@ -80,7 +79,28 @@ int main(int argc, char** argv) | |||
80 | if (class == -1) | 79 | if (class == -1) |
81 | usage("Unknown task class."); | 80 | usage("Unknown task class."); |
82 | break; | 81 | break; |
83 | 82 | case 'e': | |
83 | want_enforcement = 0; | ||
84 | break; | ||
85 | case 'r': | ||
86 | reservation = atoi(optarg); | ||
87 | break; | ||
88 | case 'o': | ||
89 | offset_ms = atof(optarg); | ||
90 | break; | ||
91 | case 'd': | ||
92 | deadline_ms = atof(optarg); | ||
93 | if (!deadline_ms || deadline_ms < 0) { | ||
94 | usage("The relative deadline must be a positive" | ||
95 | " number."); | ||
96 | } | ||
97 | break; | ||
98 | case 'v': | ||
99 | verbose = 1; | ||
100 | break; | ||
101 | case 'h': | ||
102 | usage(""); | ||
103 | break; | ||
84 | case ':': | 104 | case ':': |
85 | usage("Argument missing."); | 105 | usage("Argument missing."); |
86 | break; | 106 | break; |
@@ -95,33 +115,65 @@ int main(int argc, char** argv) | |||
95 | 115 | ||
96 | if (argc - optind < 3) | 116 | if (argc - optind < 3) |
97 | usage("Arguments missing."); | 117 | usage("Arguments missing."); |
98 | wcet = ms2ns(atoi(argv[optind + 0])); | 118 | |
99 | period = ms2ns(atoi(argv[optind + 1])); | 119 | wcet_ms = atof(argv[optind + 0]); |
120 | period_ms = atof(argv[optind + 1]); | ||
121 | |||
122 | wcet = ms2ns(wcet_ms); | ||
123 | period = ms2ns(period_ms); | ||
124 | offset = ms2ns(offset_ms); | ||
125 | deadline = ms2ns(deadline_ms); | ||
100 | if (wcet <= 0) | 126 | if (wcet <= 0) |
101 | usage("The worst-case execution time must be a " | 127 | usage("The worst-case execution time must be a " |
102 | "positive number."); | 128 | "positive number."); |
103 | if (period <= 0) | 129 | if (period <= 0) |
104 | usage("The period must be a positive number."); | 130 | usage("The period must be a positive number."); |
105 | if (wcet > period) { | 131 | if (wcet > period) { |
106 | usage("The worst-case execution time must not " | 132 | usage("The worst-case execution time must not " |
107 | "exceed the period."); | 133 | "exceed the period."); |
108 | } | 134 | } |
109 | info.exec_path = argv[optind + 2]; | 135 | |
110 | info.argv = argv + optind + 2; | ||
111 | info.wait = wait; | ||
112 | if (migrate) { | 136 | if (migrate) { |
113 | ret = be_migrate_to_domain(cluster); | 137 | ret = be_migrate_to_domain(cluster); |
114 | if (ret < 0) | 138 | if (ret < 0) |
115 | bail_out("could not migrate to target partition or cluster"); | 139 | bail_out("could not migrate to target partition or cluster."); |
116 | } | 140 | } |
117 | ret = __create_rt_task(launch, &info, cluster, wcet, period, | ||
118 | priority, class); | ||
119 | |||
120 | 141 | ||
142 | init_rt_task_param(¶m); | ||
143 | param.exec_cost = wcet; | ||
144 | param.period = period; | ||
145 | param.phase = offset; | ||
146 | param.relative_deadline = deadline; | ||
147 | param.priority = priority; | ||
148 | param.cls = class; | ||
149 | param.budget_policy = (want_enforcement) ? | ||
150 | PRECISE_ENFORCEMENT : NO_ENFORCEMENT; | ||
151 | if (migrate) { | ||
152 | if (reservation >= 0) | ||
153 | param.cpu = reservation; | ||
154 | else | ||
155 | param.cpu = domain_to_first_cpu(cluster); | ||
156 | } | ||
157 | ret = set_rt_task_param(gettid(), ¶m); | ||
121 | if (ret < 0) | 158 | if (ret < 0) |
122 | bail_out("could not create rt child process"); | 159 | bail_out("could not setup rt task params"); |
123 | else if (verbose) | ||
124 | printf("%d\n", ret); | ||
125 | 160 | ||
126 | return 0; | 161 | init_litmus(); |
162 | |||
163 | ret = task_mode(LITMUS_RT_TASK); | ||
164 | if (ret != 0) | ||
165 | bail_out("could not become RT task"); | ||
166 | |||
167 | if (verbose) | ||
168 | printf("%d\n", gettid()); | ||
169 | |||
170 | if (wait) { | ||
171 | ret = wait_for_ts_release(); | ||
172 | if (ret != 0) | ||
173 | bail_out("wait_for_ts_release()"); | ||
174 | } | ||
175 | |||
176 | execvp(argv[optind + 2], argv + optind + 2); | ||
177 | perror("execv failed"); | ||
178 | return 1; | ||
127 | } | 179 | } |
diff --git a/include/internal.h b/include/internal.h index 035440b..354f7dc 100644 --- a/include/internal.h +++ b/include/internal.h | |||
@@ -3,11 +3,6 @@ | |||
3 | 3 | ||
4 | /* low level operations, not intended for API use */ | 4 | /* low level operations, not intended for API use */ |
5 | 5 | ||
6 | /* prepare a real-time task */ | ||
7 | typedef int (*rt_setup_fn_t)(int pid, void* arg); | ||
8 | int __launch_rt_task(rt_fn_t rt_prog, void *rt_arg, | ||
9 | rt_setup_fn_t setup, void* setup_arg); | ||
10 | |||
11 | #define check(str) \ | 6 | #define check(str) \ |
12 | if (ret == -1) { \ | 7 | if (ret == -1) { \ |
13 | perror(str); \ | 8 | perror(str); \ |
diff --git a/include/litmus.h b/include/litmus.h index 8c54fdc..f99ccec 100644 --- a/include/litmus.h +++ b/include/litmus.h | |||
@@ -251,35 +251,6 @@ int init_rt_thread(void); | |||
251 | */ | 251 | */ |
252 | void exit_litmus(void); | 252 | void exit_litmus(void); |
253 | 253 | ||
254 | /* A real-time program. */ | ||
255 | typedef int (*rt_fn_t)(void*); | ||
256 | |||
257 | /** | ||
258 | * Create a real-time task that enforces exectution budgets | ||
259 | * @param rt_prog Function pointer to real-time task body | ||
260 | * @param arg Pointer to arguments to pass to the pointer in rt_prog | ||
261 | * @param cluster Cluster to schedule this task on. For partitioned scheduling, | ||
262 | * set to the desired partition. For global scheduling, set to 0 | ||
263 | * @param wcet Worst-Case execution time for this task | ||
264 | * @param period Period at which this task should be launched | ||
265 | * @param prio Priority for this task | ||
266 | */ | ||
267 | int create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, | ||
268 | lt_t wcet, lt_t period, unsigned int prio); | ||
269 | /** | ||
270 | * Create a real-time task | ||
271 | * @param rt_prog Function pointer to real-time task body | ||
272 | * @param arg Pointer to arguments to pass to the pointer in rt_prog | ||
273 | * @param cluster Cluster to schedule this task on. For partitioned scheduling, | ||
274 | * set to the desired partition. For global scheduling, set to 0 | ||
275 | * @param wcet Worst-Case execution time for this task | ||
276 | * @param period Period at which this task should be launched | ||
277 | * @param prio Priority for this task | ||
278 | * @param cls Task class (unused) | ||
279 | */ | ||
280 | int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, | ||
281 | lt_t wcet, lt_t period, unsigned int prio, task_class_t cls); | ||
282 | |||
283 | /* per-task modes */ | 254 | /* per-task modes */ |
284 | enum rt_task_mode_t { | 255 | enum rt_task_mode_t { |
285 | BACKGROUND_TASK = 0, | 256 | BACKGROUND_TASK = 0, |
@@ -8,64 +8,6 @@ | |||
8 | #include "litmus.h" | 8 | #include "litmus.h" |
9 | #include "internal.h" | 9 | #include "internal.h" |
10 | 10 | ||
11 | static void tperrorx(char* msg) | ||
12 | { | ||
13 | fprintf(stderr, | ||
14 | "Task %d: %s: %m", | ||
15 | gettid(), msg); | ||
16 | exit(-1); | ||
17 | } | ||
18 | |||
19 | /* common launch routine */ | ||
20 | int __launch_rt_task(rt_fn_t rt_prog, void *rt_arg, rt_setup_fn_t setup, | ||
21 | void* setup_arg) | ||
22 | { | ||
23 | int ret; | ||
24 | int rt_task = fork(); | ||
25 | |||
26 | if (rt_task == 0) { | ||
27 | /* we are the real-time task | ||
28 | * launch task and die when it is done | ||
29 | */ | ||
30 | rt_task = gettid(); | ||
31 | ret = setup(rt_task, setup_arg); | ||
32 | if (ret < 0) | ||
33 | tperrorx("could not setup task parameters"); | ||
34 | ret = task_mode(LITMUS_RT_TASK); | ||
35 | if (ret < 0) | ||
36 | tperrorx("could not become real-time task"); | ||
37 | exit(rt_prog(rt_arg)); | ||
38 | } | ||
39 | |||
40 | return rt_task; | ||
41 | } | ||
42 | |||
43 | int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, | ||
44 | lt_t wcet, lt_t period, unsigned int priority, task_class_t class) | ||
45 | { | ||
46 | struct rt_task params; | ||
47 | init_rt_task_param(¶ms); | ||
48 | params.cpu = domain_to_first_cpu(cluster); | ||
49 | params.period = period; | ||
50 | params.exec_cost = wcet; | ||
51 | params.cls = class; | ||
52 | params.phase = 0; | ||
53 | params.priority = priority; | ||
54 | /* enforce budget for tasks that might not use sleep_next_period() */ | ||
55 | params.budget_policy = QUANTUM_ENFORCEMENT; | ||
56 | |||
57 | return __launch_rt_task(rt_prog, arg, | ||
58 | (rt_setup_fn_t) set_rt_task_param, ¶ms); | ||
59 | } | ||
60 | |||
61 | int create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, | ||
62 | lt_t wcet, lt_t period, unsigned int prio) | ||
63 | { | ||
64 | return __create_rt_task(rt_prog, arg, cluster, wcet, period, | ||
65 | prio, RT_CLASS_HARD); | ||
66 | } | ||
67 | |||
68 | |||
69 | #define SCHED_NORMAL 0 | 11 | #define SCHED_NORMAL 0 |
70 | 12 | ||
71 | int task_mode(int mode) | 13 | int task_mode(int mode) |