You are on page 1of 4

Real-time scheduling labs 2009/2010

ENSE3

Real-Time scheduling labs


The global objective of the labs is to acquire a better understanding of the real-time
scheduling through practical programming examples. Aside the main goal youll have the
opportunity to learn some basics on real-time operating systems programming.

There are two different lab assignments corresponding to the two programming paradigms:
hardware level programming or operating system programming. That will give you the
opportunity to have a comparative view of the implementation issues in the two situations.

In both cases the problem will be the same: given a task set with specific parameters and
design constraints implement a feasible scheduler that will solve the problem (respect
the timing constraints). The hardware and software limitations (and also development time
limitations) will impose the choice of the scheduling algorithm.

Lab 1: OS programming: EDF/LLF/RM scheduling


In this part we will implement various schedulers under a Real-Time OS. The chosen OS is a
real-time Linux derivative called Xenomai. The main reason for the choice of this OS (let
alone the fact that it is free) is that Xenomai allows user mode real-time, that is, one can write
a normal program which will run in real-time mode (most RTOS allow only kernel mode
real time, i.e. the program must be an extension of the operating system itself, which is far
more difficult to program and to debug).

The Xenomai OS does not provide an EDF (or LLF) scheduler (actually only few, not to say
none, of the available RTOS provide a variable priority scheduler). We will develop one using
the existing possibilities of Xenomai.

The most useful scheduler available in Xenomai, for our application, is the fixed priority
scheduler. The general structure of our EDF (LLF) scheduler will be the following:
- define the EDF (LLF) scheduler as the highest priority task on the system
- the EDF (LLF) scheduler will run at fixed time intervals (ticks) and each instance will
be started by the fixed priority scheduler of Xenomai
- at each instance, the EDF (LLF) scheduler task will recalculate the priorities of the
other tasks according to the EDF (LLF) algorithm
- task priorities modification will force the Xenomai fixed priority scheduler to
reschedule the tasks set

Obviously, our scheduler is not optimal. It is just an EDF (LLF) layer over the system
scheduler. In order to implement an optimal EDF (LLF) scheduler (smallest overhead) one
has to go into the kernel code and modify it. However, for a reasonable precision (around
1ms), our scheduler will work fine.

Caution : In Xenomai possible priorities goes from 1 to 99, and 99 is the higher task priority.

Task model
Xenomai task model is described by a structure RT_TASK. The exact field description of the
structure is of no interest as it is not intended to be directly accessed by the user program. A
set of library functions are used instead to manipulate tasks. The main task manipulation
Real-time scheduling labs 2009/2010
ENSE3
functions calls (creation, start, delete) all already programmed in the application partial source
code that is available to you (in /usr/tp/ directory).

Additional task parameters.


The program will maintain a table of task descriptors of RT_TASK type. As Xenomai task
structures are not intended for EDF or LLF, we have to extend the task model with additional
parameters. For simplicity only basic variables types are used into the added variables. The
following tables are defined in the program:

unsigned char prios[NTASKS]; // priorities vector


unsigned char periods[NTASKS];// periods vectors
unsigned char works[NTASKS]; // computing times
unsigned char absdeadlines[NTASKS];// absolute deadline
char curdeadline[NTASKS]; // running deadlines

You may add other variables if you need.

The macro NTASKS is defined as the number of tasks excepting the scheduler. The periods,
works and absdeadlines parameters are used by the tasks for initialization. The curdeadlines
variable can be used for scheduler calculations.

Tasks code
For testing purposes, a simple task code was chosen. On initialization, each task initializes the
running deadline with its absolute deadline. Then turn itself into a periodic task with a period
multiple of 10ms. At the end of initialization the task in blocked by a system semaphore.
When all the tasks are initialized the system will release the semaphore and all the tasks will
start.

The actual task code is an infinite loop. Each loop has duration of computing time * 10ms
(which corresponds to a task instance) divided in internal loops of 10ms each (look at the
code of demo function). After each 10ms slice the task will print some statistics allowing you
to interpret the scheduling. At the end of each instance the task will print a message,
reinitialize the running deadline to the absolute deadline then go inactive until the next period.

Scheduler algorithm
Scheduler initialization is similar with task initialization, excepting that the scheduler is
programmed to run every 10ms. At each instance the scheduler has to check the status of the
tasks. If a task is ready it has to decrement task running deadline then compute and set the
new task priority. If the task is not active then set the priority to the lowest system priority.
The task status is retrieved in a structure of type RT_TASK_INFO by a library call
rt_task_inquire. The syntax is the following :
rt_task_inquire(task pointer, rt_task_info structure pointer)
The task pointers are stored in the global variable:
RT_TASK demo_task[NTASKS]
and the task_info in the global variable (see the code)
RT_TASK_INFO infotask[NTASKS]
The status of the task is stored in the status field of the RT_TASK_INFO structure. The
value of the field is a superposition of several values (logical OR). In order to test if the task is
ready one should test if the value T_READY is present.
Real-time scheduling labs 2009/2010
ENSE3
Once the new priority is computed it can be set by the use of another library function :
rt_task_set_priority. Its syntax is :
rt_task_set_priority(task pointer, priority);
where priority is between 1 and 98 (99 is reserved for the scheduler task).
Finally the scheduler goes inactive until the next period.

Work to do
The partial application code is available in /usr/tp/edfs.c. Copy the file in your directory.
- Write on paper the scheduler algorithm
- Localize the code of the scheduler into the source file.
- Code the scheduler, once at a time. Start with EDF than LLF, eventually RM.
- Compile linking with Xenomai libraries. A script is available. Type in command line:

comp-xeno edfs (replace edfs with your program name)

- Test the program using the data of the two EDF case studies presented in the course
(slides 59 et 60)
- Compare the complexity of the 3 schedulers.

LAB 2. Direct hardware programming: Fixed priority co-


operative scheduler
For small devices (like microcontroller) severe resource limitations (essentially the stack)
made difficult the implementation of pre-emptive schedulers. It could be achieved, but at a
supplementary programming cost and performance loss (use of software stacks). On our target
microcontroller board the stack is limited to 256 bytes and the context is at least 15 bytes.

Knowing that potential function calls, interruptions, and the scheduler itself will also need
some stack, direct hardware stack usage is not allowable. On the other hand, software stacks
implementation needs a lot of code which is not feasible for our limited development time.
Then, we will turn out to a different scenario.

If the tasks to schedule have roughly the same computing time, which is relatively small
compared to the periods, a non-pre-emptive scheduler can be used. In this case, only the
priority at starting time has to be considered by the scheduler.

Task model
The programming model of a task is quite simple. To each task a structure of the following
type is associated :

typedef data struct


{
void (code * pTask)(void); // Pointer to the task function
int Delay; // Delay (ticks) until the next run
tWord Period; // Interval (ticks) between runs.
tWord Priority; // Task priority, 0 is the higher priority
tByte RunMe; // Permission to run
} sTask;
Real-time scheduling labs 2009/2010
ENSE3
On task initialisation the scheduler will fill a sTask structure for each task. The function
pointer points to the single loop functions code. The tWord and tByte types are aliases for
unsigned int and unsigned char.

Scheduler model
Two functions are at the core of the scheduler: the Update and the Dispatch functions. In
short: the Update function will select the highest priority task to run between the ready tasks.
The Dispacher will run the task selected by the Updater.

Detailed scheduler behaviour.

Updater function.

On every scheduler tick (which is programmed on an interruption), the Updater will scan the
task lists and search for the ready tasks. A task is ready if its Delay parameter is less than or
equal to zero. After checking the Updater will decrement the Delay parameter. Between the
ready tasks, and if the processor is idle (the ProcIdle global variable is set) the Updater will
select the highest priority task and schedule it. A task is scheduled to run if the RunMe
parameter is set to one.
Dispatcher function

When the processor is idle the dispatcher function will scan the tasks list, search for the
scheduled task and execute it. At the end of the task execution it will acknowledge the task
execution (reset RunMe parameter) and signal the processor idle (set the ProcIdle global
variable).

Work to do
- Write on paper the algorithm of your two scheduler core functions.
- Locate in the development project the Updater and Dispatcher functions and
implement the corresponding code
- Test your scheduler for several tasks configurations. For each task configuration
provide a hand made execution chronogram over the major scheduling cycle.
Note
Some sample tasks are provided with the code. Each task will display a number on the seven
segment display for a quite constant duration then switch off the display. You can vary the
tasks durations and priorities.

Report
Youll provide one single report for both labs. The report will include:
- your algorithms,
- the code,
- the description of your work,
- the scheduling problems youve tested
- a comparison between the two programming method.

Also, please include your personal opinions on the labs.

You might also like