aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Erickson <jerickso@cs.unc.edu>2012-08-22 18:55:51 -0400
committerJeremy Erickson <jerickso@cs.unc.edu>2012-08-22 18:55:51 -0400
commit82e55e27d4eab2388ee6aee447bb10cfc4058d86 (patch)
tree81445de20a5466c18b9f9ba4e2ee3a60a338257f
parentda7a2586be45bc784480c440fd8d627a796df671 (diff)
Add FMLP Test Task
-rw-r--r--Makefile5
-rw-r--r--bin/fmlp_test_task.c281
2 files changed, 285 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 2109a45..031a3ac 100644
--- a/Makefile
+++ b/Makefile
@@ -70,7 +70,7 @@ AR := ${CROSS_COMPILE}${AR}
70# Targets 70# Targets
71 71
72all = lib ${rt-apps} 72all = lib ${rt-apps}
73rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \ 73rt-apps = cycles base_task rt_launch rtspin fmlp_test_task release_ts measure_syscall \
74 base_mt_task runtests 74 base_mt_task runtests
75 75
76.PHONY: all lib clean dump-config TAGS tags cscope help 76.PHONY: all lib clean dump-config TAGS tags cscope help
@@ -211,6 +211,9 @@ obj-rt_launch = rt_launch.o common.o
211obj-rtspin = rtspin.o common.o 211obj-rtspin = rtspin.o common.o
212lib-rtspin = -lrt 212lib-rtspin = -lrt
213 213
214obj-fmlp_test_task = fmlp_test_task.o common.o
215lib-fmlp_test_task = -lrt
216
214obj-release_ts = release_ts.o 217obj-release_ts = release_ts.o
215 218
216obj-measure_syscall = null_call.o 219obj-measure_syscall = null_call.o
diff --git a/bin/fmlp_test_task.c b/bin/fmlp_test_task.c
new file mode 100644
index 0000000..6f8e2ec
--- /dev/null
+++ b/bin/fmlp_test_task.c
@@ -0,0 +1,281 @@
1/* based_mt_task.c -- A basic multi-threaded real-time task skeleton.
2 *
3 * This (by itself useless) task demos how to setup a multi-threaded LITMUS^RT
4 * real-time task. Familiarity with the single threaded example (base_task.c)
5 * is assumed.
6 *
7 * Currently, liblitmus still lacks automated support for real-time
8 * tasks, but internaly it is thread-safe, and thus can be used together
9 * with pthreads.
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14/* Extras */
15#include <stdint.h>
16#include <unistd.h>
17#include <assert.h>
18#include <errno.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22
23/* Include gettid() */
24#include <sys/types.h>
25
26/* Include threading support. */
27#include <pthread.h>
28
29/* Include the LITMUS^RT API.*/
30#include "litmus.h"
31
32/* Let's create 4 threads in the example,
33 */
34#define NUM_THREADS 4
35#define MAX_PHASES 10
36
37/* The information passed to each thread. Could be anything. */
38struct thread_context {
39 int id;
40 int fd;
41 int semaphore;
42 lt_t exec;
43 lt_t period;
44 int split;
45 int phases;
46 double initial_phase;
47 double locked[MAX_PHASES];
48 double unlocked[MAX_PHASES];
49};
50
51/* The real-time thread program. Doesn't have to be the same for
52 * all threads. Here, we only have one that will invoke job().
53 */
54void* rt_thread(void *tcontext);
55
56/* Declare the periodically invoked job.
57 * Returns 1 -> task should exit.
58 * 0 -> task should continue.
59 */
60int job(struct thread_context* ctx);
61
62
63/* Catch errors.
64 */
65#if 0
66#define CALL( exp ) do { \
67 int ret; \
68 ret = exp; \
69 if (ret != 0) \
70 fprintf(stderr, "%s failed: %m\n", #exp);\
71 else \
72 fprintf(stderr, "%s ok.\n", #exp); \
73 } while (0)
74#endif
75#define CALL( exp ) exp
76
77/* Basic setup is the same as in the single-threaded example. However,
78 * we do some thread initiliazation first before invoking the job.
79 */
80int main(int argc, char** argv)
81{
82 int i;
83 struct thread_context ctx[NUM_THREADS];
84 pthread_t task[NUM_THREADS];
85 int fd;
86
87 /* The task is in background mode upon startup. */
88
89
90 /*****
91 * 1) Command line paramter parsing would be done here.
92 */
93
94
95
96 /*****
97 * 2) Work environment (e.g., global data structures, file data, etc.) would
98 * be setup here.
99 */
100
101
102
103 /*****
104 * 3) Initialize LITMUS^RT.
105 * Task parameters will be specified per thread.
106 */
107 fd = open("semaphores", O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
108 CALL( init_litmus() );
109
110
111 /*****
112 * 4) Launch threads.
113 */
114
115 ctx[0].id = 0;
116 ctx[0].fd = fd;
117 ctx[0].exec = 10000000;
118 ctx[0].period = 20000000;
119 ctx[0].split = 5;
120 ctx[0].phases = 1;
121 ctx[0].initial_phase = .0025;
122 ctx[0].locked[0] = .003;
123 ctx[0].unlocked[0] = .0045;
124
125 ctx[1].id = 1;
126 ctx[1].fd = fd;
127 ctx[1].exec = 10000000;
128 ctx[1].period = 20000000;
129 ctx[1].split = 5;
130 ctx[1].phases = 1;
131 ctx[1].initial_phase = .003;
132 ctx[1].locked[0] = .002;
133 ctx[1].unlocked[0] = .005;
134
135 ctx[2].id = 2;
136 ctx[2].fd = fd;
137 ctx[2].exec = 4000000;
138 ctx[2].period = 10000000;
139 ctx[2].split = 1;
140 ctx[2].phases = 0;
141 ctx[2].initial_phase = .004;
142
143 ctx[3].id = 3;
144 ctx[3].fd = fd;
145 ctx[3].exec = 4000000;
146 ctx[3].period = 10000000;
147 ctx[3].split = 1;
148 ctx[3].phases = 0;
149 ctx[3].initial_phase = .004;
150
151 for (i = 0; i < NUM_THREADS; i++){
152 pthread_create(task + i, NULL, rt_thread, (void *) (ctx + i));
153 }
154
155
156 /*****
157 * 5) Wait for RT threads to terminate.
158 */
159 for (i = 0; i < NUM_THREADS; i++)
160 pthread_join(task[i], NULL);
161
162
163 /*****
164 * 6) Clean up, maybe print results and stats, and exit.
165 */
166 return 0;
167}
168
169
170
171/* A real-time thread is very similar to the main function of a single-threaded
172 * real-time app. Notice, that init_rt_thread() is called to initialized per-thread
173 * data structures of the LITMUS^RT user space libary.
174 */
175void* rt_thread(void *tcontext)
176{
177 int do_exit = 0;
178 struct thread_context *ctx = (struct thread_context *) tcontext;
179
180 /* Make presence visible. */
181 printf("RT Thread %d active.\n", ctx->id);
182
183 /*****
184 * 1) Initialize real-time settings.
185 */
186 CALL( init_rt_thread() );
187
188 ctx->semaphore = open_fmlp_sem(ctx->fd, 0);
189 CALL( sporadic_task_ns(ctx->exec, ctx->period, 0, ctx->split, 0,
190 RT_CLASS_HARD, PRECISE_ENFORCEMENT, 0));
191
192
193 /*****
194 * 2) Transition to real-time mode.
195 */
196 CALL( task_mode(LITMUS_RT_TASK) );
197
198 /* The task is now executing as a real-time task if the call didn't fail.
199 */
200
201 printf("[%d] Waiting for TS release.\n ", ctx->id);
202 wait_for_ts_release();
203
204
205 /*****
206 * 3) Invoke real-time jobs.
207 */
208 do {
209 /* Wait until the next job is released. */
210 sleep_next_period();
211 /* Invoke job. */
212 do_exit = job(ctx);
213 } while (!do_exit);
214
215
216
217 /*****
218 * 4) Transition to background mode.
219 */
220 CALL( task_mode(BACKGROUND_TASK) );
221
222
223 return NULL;
224}
225
226#define NUMS 4096
227static int num[NUMS];
228
229static int loop_once(void)
230{
231 int i, j = 0;
232 for (i = 0; i < NUMS; i++)
233 j += num[i]++;
234 return j;
235}
236
237static int loop_for(double exec_time, double emergency_exit)
238{
239 double last_loop = 0, loop_start;
240 int tmp = 0;
241
242 double start = cputime();
243 double now = cputime();
244 while (now + last_loop < start + exec_time) {
245 loop_start = now;
246 tmp += loop_once();
247 now = cputime();
248 last_loop = now - loop_start;
249 if (emergency_exit && wctime() > emergency_exit) {
250 /* Oops --- this should only be possible if the execution time tracking
251 * is broken in the LITMUS^RT kernel. */
252 fprintf(stderr, "!!! fmlp_test_task/%d emergency exit!\n", getpid());
253 fprintf(stderr, "Something is seriously wrong! Do not ignore this.\n");
254 break;
255 }
256 }
257
258 return tmp;
259}
260
261int job(struct thread_context* ctx)
262{
263 int i;
264 /* Do real-time calculation. */
265 double emergency_exit = ctx->initial_phase;
266 for (i = 0; i < ctx->phases; i++) {
267 emergency_exit += ctx->locked[i];
268 emergency_exit += ctx->unlocked[i];
269 }
270 emergency_exit *= 200;
271 emergency_exit += wctime();
272 loop_for(ctx->initial_phase, emergency_exit);
273 for (i = 0; i < ctx->phases; i++) {
274 CALL( litmus_lock( 0 ));
275 loop_for(ctx->locked[i], emergency_exit);
276 CALL( litmus_unlock( 0 ));
277 loop_for(ctx->unlocked[i], emergency_exit);
278 }
279 /* Don't exit. */
280 return 0;
281}