Modern real-time systems are based on the complementary concepts of multitasking and intertask communications. A multitasking environment allows real-time applications to be constructed as a set of independent tasks, each with a separate thread of execution and its own set of system resources. The intertask communication facilities allow these tasks to synchronize and coordinate their activities. The Xenomai multitasking scheduler uses interrupt-driven, priority-based preemptive task scheduling. It features fast context switch time and low interrupt latency.
The following are the primary objectives of this exercise:
Multitasking creates the appearance of many concurrently executing tasks wheras, in fact, the kernel interleaves their execution on the basis of a scheduling algorithm. Each task has its own context, which is the CPU environment and system resources that the task sees each time it is scheduled to run by the kernel. On a context switch, the context of a task is saved in the Task Control Block (TCB). The context of a task includes:
RTIME now; now = rt_timer_read();
A task can be scheduled in two ways.
int rt_task_set_periodic(RT_TASK *task, RTIME start_time, RTIME period);
void rt_task_wait_period(NULL);
As an example, consider a task function which executes an infinite loop which typically reads some inputs, computes some outputs and waits for the next period. Typical code looks like this:
void task_function(void *arg) { rt_task_set_periodic(NULL, TM_NOW, period_ns); while (1) { /* Do your thing here */ rt_task_wait_period(NULL); } return; }
Write a program which runs five tasks, e.g. use
#define NTASKS 5 RT_TASK task[NTASKS];Give all tasks a different name and run them with the same priority in one-shot mode. Each task executes the following function :
void demo(void *arg) { RT_TASK_INFO curtaskinfo; rt_task_inquire(NULL,&curtaskinfo); rt_printf("Task name: %s ", curtaskinfo.name); }
Execute the program and describe the resulting output.
Note that the demo task has an argument arg
which is a
pointer to type void. An integer argument can be passed as a reference to a
task during the call to rt_task_start()
.
For instance, for a variable int
index
, use
rt_task_start(&taskd.., &demo, &index)
Modify the program of exercise 2a such that a unique argument is provided to each of the five tasks. Let the tasks print this number by casting and derefencing the number using, for instance,
int num = * (int *)arg;
Again, each task has the same priority. Execute the program and describe its output.
RTIME sec = 1e9;and insert in each task before
int num = * (int *)arg;
a real-time sleep statement
rt_task_sleep(sec);
To avoid termination when the main loop stops, end the main loop with the statements:
printf("End program by CTRL-C\n"); pause();
Execute the program and describe the resulting output.
Modify the program of exercise 2b by assigning each task a unique priority such that the task which is started first gets the lowest priority and tasks started later get higher priority. Is there any difference in output? Has the order in which the five tasks print their message changed? If not, explain why.
Rewrite the program of exercise 2b into one where three tasks are running
periodically with periods of 1, 2 and 3 seconds, respectively. All tasks have
the same priority; they should start with an rt_task_sleep
of 1
second and next execute a loop in which they print a message and wait for the next period.
Similar to exercise 2c, add a pause()
to avoid termination when main
ends.
Explain the resulting output.
Last Updated: 24 May 2019 (by Jozef Hooman)
Created by: Harco Kuppens
h.kuppens@cs.ru.nl