CS452 - Real-Time Programming - Spring 2009

Lecture 4 - Kernel, Tasks

Practical Detail


Train RS-232

Three wire works fine as long as both ends of the wire are much faster than the wire itself. But the train controller is very slow. Why?

The train controller needs to be able to say STOP. How is this done?

Software Flow Control


Hardware Flow Control



What Happens if You Omit Flow Control

Kernel of a Real-time Operating System


What Does the Kernel Provide



Communication has two sides

  1. sharing information
  2. handshaking

We use Send/Receive/Reply (SRR) to do both.

  1. Send blocks
  2. Receive blocks: is synchronous with the call to send
  3. Reply doesn't block: is synchronous with the return from send



  1. Between tasks
  2. With internal events
  3. With external events

Kernel Structure

The kernel is just a function like any other, but which runs forever.

kernel( ) {
  initialize( );
    request = getNextRequest( );
    handle( request );

This hides all the interesting stuff inside

int getNextRequest( ) {
  active = schedule( ); //active is a pointer to a TD
  nextRequest = activate( active ); //the active task doesn't change
  return nextRequest;

What's inside activate( active )?

  1. transfer of control to the active task
  2. execution to completion of the active task
  3. transfer of control back to the kernel
  4. getting the request

The hard part to get right is `transfer of control'

How I Get Started Writing a Context Switch

1. Start with a program that calls a function

void func( ) {
  printf( "func: running\n" );

void main( ) {
  printf( "main: beginning\n" );
  func( );
  printf( "main: ending\n" );
  1. Compile and run it.
  2. Compile with the -S flag and look at the assembly code.

2. Find out how to put a PC into an interrupt vector

What is an interrupt vector?

  1. Add to the assembly code a line that puts the address of the first instruction of func( ) into the interrupt vector
  2. Compile the assembly code and run it.

3. Change to calling func() using an interrupt

  1. Replace the instruction in main that calls func( ) to int n
  2. Replace the ret instruction in func( ) with iret.

4. You have just written a context switch, now you need to dress it up.

  1. Add stuff to main( ) so that it has context
  2. Save the context of main( ) on the stack just before int n.
  3. Restore the context of main( ) from the stack just after int n.

5. Add a return value from func( ) and pick it up in main( ).

To go beyond this we need to think about tasks.


Kernel maintains a task descriptor (TD) for each created task. That is, to create a task the kernel must allocate a TD and initialize it. The TD normally contains

  1. The task's stack pointer, which points to a private stack containing

    all ready to be reloaded whenever the task next runs.

  2. Possibly the return value for when the task is next activated
  3. The task's parent
  4. The task's state

Possible states of the task

  1. Active: running or about to run
  2. Ready: can run if scheduled
  3. Blocked: waiting for something to happen


Return to: