/* 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 #include #include /* Include gettid() */ #include /* Include threading support. */ #include /* Include the LITMUS^RT API.*/ #include "litmus.h" #define PERIOD 100 #define RELATIVE_DEADLINE 100 #define EXEC_COST 10 #define NS_PER_MS 1e6 /* Let's create 10 threads in the example, * for a total utilization of 1. */ #define NUM_THREADS 10 /* The information passed to each thread. Could be anything. */ struct thread_context { int id; }; /* 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(void); /* 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; 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; /* Set up task parameters */ memset(¶m, 0, sizeof(param)); param.exec_cost = EXEC_COST * NS_PER_MS; param.period = PERIOD * NS_PER_MS; param.relative_deadline = RELATIVE_DEADLINE * NS_PER_MS; param.cls = RT_CLASS_SOFT; param.budget_policy = NO_ENFORCEMENT; /* 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(). */ 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(); } while (!do_exit); /***** * 4) Transition to background mode. */ CALL( task_mode(BACKGROUND_TASK) ); return NULL; } int job(void) { /* Do real-time calculation. */ /* Don't exit. */ return 0; }