The default scheduling policy in Xenomai is preemptive priority-based FIFO scheduling. Hence, the execution of a low-priority task is interrupted when a high-priority is ready to execute. When multiple tasks of the same priority are ready to run, the default is that the task which was first queued in the waiting queue of the scheduler, is run first (FIFO ordering), and is run to its end. In the next exercise we show how this can be changed to round-robin scheduling of tasks with equal priority.
The following are the primary objectives of this exercise:
With a preemptive priority-based scheduler, each task has a priority and the kernel ensures that the CPU is allocated to the highest priority task that is ready to run. This scheduling method is preemptive in that if a task that has a higher priority than the current task, it becomes ready to run. The kernel saves the context of the current task and switches to the context of the higher priority task. The Xenomai kernel has priority levels between the highest priority 99 and the lowest priority 1.
When creating a task with rt_task_create(..) one of the arguments to set is the priority at which the task is to execute. The priority of a task can be changed by means of the following function:
int rt_task_set_priority(RT_TASK *task, int prio)
The next example program contains three tasks with different priorities. Each task has an execution duration of EXECTIME in ns. After each SPINTIME in ns a message is printed. The CPU is kept busy by the function
void rt_timer_spin(RTIME ns)which is a busy wait burning CPU cycles.
------------------------------------------------------------------------------------ #include <stdio.h> #include <signal.h> #include <unistd.h> #include <alchemy/task.h> #include <alchemy/sem.h> #include <alchemy/timer.h> #define NTASKS 3 #define HIGH 52 /* high priority */ #define MID 51 /* medium priority */ #define LOW 50 /* low priority */ RT_TASK demo_task[NTASKS]; RT_SEM mysync; #define EXECTIME 2e8 // execution time in ns #define SPINTIME 1e7 // spin time in ns void demo(void *arg) { RTIME starttime, runtime; RT_TASK_INFO taskinfo; int num=*(int *)arg; printf("Task : %d\n",num); rt_sem_p(&mysync,TM_INFINITE); runtime = 0; while(runtime < EXECTIME) { rt_timer_spin(SPINTIME); // spin cpu doing nothing runtime = runtime + SPINTIME; printf("Running Task : %d at ms : %d\n",num, runtime/1000000); } printf("End Task : %d\n",num); } //startup code void startup() { int i; char str[20] ; // semaphore to sync task startup on rt_sem_create(&mysync,"MySemaphore",0,S_FIFO); for(i=0; i < NTASKS; i++) { printf("start task : %d\n",i); sprintf(str,"task%d",i); rt_task_create(&demo_task[i], str, 0, 50, 0); rt_task_start(&demo_task[i], &demo, &i); } // assign priorities to tasks rt_task_set_priority(&demo_task[0],LOW); rt_task_set_priority(&demo_task[1],MID); rt_task_set_priority(&demo_task[2],HIGH); printf("wake up all tasks\n"); rt_sem_broadcast(&mysync); } int main(int argc, char* argv[]) { startup(); printf("\nType CTRL-C to end this program\n\n" ); pause(); }
Download example program ex04a.c above. Execute it, describe and explain its output.
Experiment 4b.
Modify the program of 4a such that the first task (i.e., task 0) still has the lowest priority, but the other two tasks are running at the same higher priority. Compare the output with that of 4a.
Modify the program of 4a such that the highest-priority task half-way its execution:
Explain the output.
Modify the program of 4a such that each task in the middle of its execution
changes its priority. The first task (i.e., task 0) changes its priority halfway
to 40, the second task to 39 and the third to 38. Explain the resulting output.
Last Updated: 18 May 2022 (Mathijs Schuts)
Created by: Harco Kuppens
h.kuppens@cs.ru.nl