/* based_mt_task.c -- A basic multi-threaded real-time task skeleton.
*
* This (by itself useless) task demos how to setup a multi-threaded LITMUS^RT
* real-time task. Familiarity with the single threaded example (base_task.c)
* is assumed.
*
* Currently, liblitmus still lacks automated support for real-time
* tasks, but internaly it is thread-safe, and thus can be used together
* with pthreads.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Include gettid() */
#include <sys/types.h>
/* Include threading support. */
#include <pthread.h>
/* Include the LITMUS^RT API.*/
#include "litmus.h"
#define PERIOD 100
#define RELATIVE_DEADLINE 100
#define EXEC_COST 10
/* Let's create 10 threads in the example,
* for a total utilization of 1.
*/
#define NUM_THREADS 3
/* The information passed to each thread. Could be anything. */
struct thread_context {
int id;
int cpu;
int job_no;
};
/* The real-time thread program. Doesn't have to be the same for
* all threads. Here, we only have one that will invoke job().
*/
void* rt_thread(void *tcontext);
/* Declare the periodically invoked job.
* Returns 1 -> task should exit.
* 0 -> task should continue.
*/
int job(struct thread_context *tcx);
/* Catch errors.
*/
#define CALL( exp ) do { \
int ret; \
ret = exp; \
if (ret != 0) \
fprintf(stderr, "%s failed: %m\n", #exp);\
else \
fprintf(stderr, "%s ok.\n", #exp); \
} while (0)
/* Basic setup is the same as in the single-threaded example. However,
* we do some thread initiliazation first before invoking the job.
*/
int main(int argc, char** argv)
{
int i;
struct thread_context ctx[NUM_THREADS];
pthread_t task[NUM_THREADS];
/* The task is in background mode upon startup. */
/*****
* 1) Command line paramter parsing would be done here.
*/
/*****
* 2) Work environment (e.g., global data structures, file data, etc.) would
* be setup here.
*/
/*****
* 3) Initialize LITMUS^RT.
* Task parameters will be specified per thread.
*/
init_litmus();
/*****
* 4) Launch threads.
*/
for (i = 0; i < NUM_THREADS; i++) {
ctx[i].id = i;
ctx[i].cpu = 0;
ctx[i].job_no = 0;
pthread_create(task + i, NULL, rt_thread, (void *) (ctx + i));
}
/*****
* 5) Wait for RT threads to terminate.
*/
for (i = 0; i < NUM_THREADS; i++)
pthread_join(task[i], NULL);
/*****
* 6) Clean up, maybe print results and stats, and exit.
*/
return 0;
}
/* A real-time thread is very similar to the main function of a single-threaded
* real-time app. Notice, that init_rt_thread() is called to initialized per-thread
* data structures of the LITMUS^RT user space libary.
*/
void* rt_thread(void *tcontext)
{
int do_exit;
struct thread_context *ctx = (struct thread_context *) tcontext;
struct rt_task param;
int ret;
/* Set up task parameters */
init_rt_task_param(¶m);
param.exec_cost = ms2ns(EXEC_COST);
param.period = ms2ns(PERIOD);
param.relative_deadline = ms2ns(RELATIVE_DEADLINE);
/* What to do in the case of budget overruns? */
param.budget_policy = NO_ENFORCEMENT;
/* The task class parameter is ignored by most plugins. */
param.cls = RT_CLASS_SOFT;
/* The priority parameter is only used by fixed-priority plugins. */
param.priority = LITMUS_LOWEST_PRIORITY;
/* Make presence visible. */
printf("RT Thread %d active.\n", ctx->id);
/*****
* 1) Initialize real-time settings.
*/
CALL( init_rt_thread() );
/* To specify a partition, do
*
* param.cpu = CPU;
* be_migrate_to(CPU);
*
* where CPU ranges from 0 to "Number of CPUs" - 1 before calling
* set_rt_task_param().
*/
param.cpu = ctx->cpu;
ret = be_migrate_to_cpu(ctx->cpu);
if (ret < 0) {
printf("RT Thread %d fails to migrate to CPU%d\n", ctx->id, ctx->cpu);
return NULL;
}
CALL( set_rt_task_param(gettid(), ¶m) );
/*****
* 2) Transition to real-time mode.
*/
CALL( task_mode(LITMUS_RT_TASK) );
/* The task is now executing as a real-time task if the call didn't fail.
*/
/*****
* 3) Invoke real-time jobs.
*/
do {
/* Wait until the next job is released. */
sleep_next_period();
/* Invoke job. */
do_exit = job(ctx);
} while (!do_exit);
/*****
* 4) Transition to background mode.
*/
CALL( task_mode(BACKGROUND_TASK) );
return NULL;
}
int job(struct thread_context *tcx)
{
/* Do real-time calculation. */
printf("Job executinig\n");
tcx->job_no++;
if (tcx->job_no == 5)
return 1;
/* Don't exit. */
return 0;
}