For task with equal priority, the Xenomai scheduler supports both FIFO scheduling and round-robin policies. The round-robin policy is similar to a time-sharing operating system runs each active process in turn for its share of time (its "timeslice").
The following are the primary objectives of this exercise:
With FIFO scheduling, a task will only preempt a task with a lower priority; it never preempts a task with the same or lower priority. When multiple tasks of the same priority are ready to run, the one which was queued first in the waiting queue of the scheduler, is run first (following FIFO ordering). Only when the first task is ready, the scheduler may execute the second waiting task from the waiting queue.
A round-robin scheduling algorithm tries to achieve fair scheduling among all ready tasks with the same priority. Without round-robin scheduling, a single task can usurp the processor by never blocking and, hence, never giving other equal priority tasks a chance to run.
Round-robin scheduling achieves fair allocation of the CPU to tasks of the same priority by an approach known as time slicing. Each task executes for a defined interval or time slice; then another task executes for an equal interval, in rotation. The allocation is fair in that no task of a priority group gets a second slice of time before the other tasks of a group are given a slice.
Round-robin scheduling can be enabled with a call to the following function
rt_task_set_mode(0,T_RRB ,NULL);
and a call to
rt_task_slice(task_descr,quantum)
to set the round robin time slice interval value to quantum clock ticks (because of legacy reasons, this quantum has to be specified in terms of jiffies - see exercise 2). This interval is the amount of time each task is allowed to run before relinquishing the processor to another equal priority task. Argument task_desc is the task descriptor at which the round robin interval is set.
Note: with the function rt_task_set_mode one can also disable round robin scheduling again.
In the example below, three tasks with the same priority print their task ids on the console, similar to the example program of exercise 6. Because round-robin requires jiffies, the task timing part has been changed.
------------------------------------------------------------------------------------
/* ex07a.c */
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include <native/task.h>
#include <native/timer.h>
#include <native/sem.h>
#include <rtdk.h>
#include <sys/io.h>
#define NTASKS 3
RT_TASK demo_task[NTASKS];
RT_
// set new baseperiod for the clock :
// - clock only increments
counter when a base period is passed
// - the unit of the clock
counter is called a jiffie, which in fact
// represents that a baseperiod
is passed
// e.g. If 10 baseperiods
are passed, the clock gives an increase
// in 10 jiffies
#define BASEPERIOD 1e6 // baseperiod in
ns.
// when base period is set,
all times in the api are
expressed in jiffies
#define EXECTIME 200
// execution time in jiffies
#define SPINTIME 10
// spin time in jiffies
void demo(void *arg)
{
RTIME starttime,
runtime;
int
num=*(int *)arg;
RT_TASK *curtask;
RT_TASK_
rt_printf("Task : %d\n",num);
rt_sem_p(&mysync,TM_INFINITE);
// let the task run RUNTIME(=200)
jiffies in steps of SPINTIME(=20) jiffies
runtime = 0;
while(runtime <
EXECTIME) {
rt_timer_spin(SPINTIME*BASEPERIOD); // spin cpu doing
nothing
// note: rt_timer_spin
function does not accept jiffies only nanoseconds
//
deviates from timing conventions throughout the Xenomai
runtime =
runtime + SPINTIME;
rt_printf("Running Task :
%d at time : %d\n",num,runtime);
}
rt_printf("End Task : %d\n",num);
}
//startup code
void startup()
{
int
i;
char str[10] ;
// semaphore to sync task startup on
rt_sem_create(&mysync,"MySemaphore",0,S_FIFO);
// change to period mode because round robin
does not work
// in one shot mode
rt_timer_set_mode(BASEPERIOD);// set tick
period
for(i=0; i < NTASKS; i++) {
rt_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);
}
rt_printf("wake up all tasks\n");
rt_sem_broadcast(&mysync);
}
void init_xenomai()
{
/* Avoids memory
swapping for this program */
mlockall(
/* Perform auto-init
of rt_print buffers if the task doesn't do so */
rt_print_auto_init(1);
}
int main(int
argc, char* argv[])
{
printf("\nType CTRL-C to end this
program\n\n" );
// code to set things to run xenomai
init_xenomai();
//startup code
startup();
// wait for CTRL-c is typed to end the
program
pause();
}
------------------------------------------------------------------------------------
Exercises
Run the program above and observe its behaviour.
Schedule all three tasks according to the round robin policy and explain the output.
Add a fourth task which is the same as the other three tasks, but has a priority of 80. Describe and explain the output from running the program. Does it make a difference whether task four uses the round-robin policy or not? Explain why.
Last Updated:
Created by:
h.kuppens@cs.ru.nl