Real-time Linux (Xenomai)

 Radboud University Nijmegen

Exercise #6: Preemptive Priority-Based Scheduling


Introduction

The default scheduling policy in Xenomai is preemptive priority-based FIFO scheduling. Hence, execution of a low-priority task is interrupted when a high-priority is ready to execute. When multiple processes 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 run to its end. In the next exercise we show how this can be changed to round-robin scheduling of tasks with equal priority.


Objectives

The following are the primary objectives of this exercise:

  • To demonstrate the use of Xenomai preemptive priority based task scheduling facilities.

Description 

Preemptive Priority-Based Scheduling 

With a preemptive priority-based scheduler, each task has a priority and the kernel insures 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 becomes ready to run, the kernel saves the context of the current tasks 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 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)

Example: Priority-Based Scheduling

The next example program contains three tasks with different priorities. Each task has an execution of  EXECTIME ns in which after each SPINTIME 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.

------------------------------------------------------------------------------------


/* ex06a.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

 

#define HIGH 52 /* high priority */

#define MID 51 /* medium priority */

#define LOW 50  /* low priority */

 

RT_TASK demo_task[NTASKS];

RT_SEM mysync;

 

#define BASEPERIOD 0   // baseperiod 0 to get ns

 

#define EXECTIME   2e8   // execution time in ns

#define SPINTIME   1e7   // spin time in ns

 

void demo(void *arg)

{

    RTIME starttime, runtime;

    int num=*(int *)arg;

    RT_TASK *curtask;

    RT_TASK_INFO curtaskinfo;

 

    rt_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;

 

      rt_printf("Running Task  : %d  at ms : %d\n",num,runtime/1000000);

    }

    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);

 

  // set timing to ns

  rt_timer_set_mode(BASEPERIOD);

 

  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);

  }

  // assign priorities to tasks

  // (or in creation use 50+i)

  rt_task_set_priority(&demo_task[0],LOW);

  rt_task_set_priority(&demo_task[1],MID);

  rt_task_set_priority(&demo_task[2],HIGH);

 

  rt_printf("wake up all tasks\n");

  rt_sem_broadcast(&mysync);

}

 

void init_xenomai() {

  /* Avoids memory swapping for this program */

  mlockall(MCL_CURRENT|MCL_FUTURE);

 

  /* 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

Exercise 6a.

Execute the example program above and explain its output.

Experiment 6b.

Modify the program of 6a such that first task still has the lowest priority, but the other two tasks are running at the same high priority. Compare the output with that of 6a.

Experiment 6c.

Modify the program of 6a such that the highest-priority task half-way its execution:

  • first raises the priority of the  middle-priority task with 10 and
  • next immediately also raises the priority of the low-priority task with 10.

Explain the output.

Experiment 6d.

Modify the program of 6a such that each task at  half-way of its execution changes its priority. The first task changes it priority halfway to 40, the second task to 39 and the third to 38. Explain the resulting output.


Last Updated: 29 August 2009                         (Harco Kuppens)
Created by: Harco Kuppens
h.kuppens@cs.ru.nl