CS452 - Real-Time Programming - Spring 2011

Lecture 4 - Tasks, Kernels

Pubilic Service Announcements

  1. Partners
  2. Work off campus: IPAQ

Kernel of a Real-time Operating System


The real-time operating system we build consists of

  1. an uninterruptible microkernel, plus
  2. interruptible device-handling server tasks that run in user-space with permissions allowing them to access hardware.

What Does a Microkernel Provide?



Communication has two aspects

  1. sharing information, requesting service
  2. synchronization

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


Input from the outside world

  1. Provide the information you polled for
  2. ISR OS design, which is essentially a jump table, which separates testing from acting
    interrupt entry point:
        calculate action_entry_point;
        jump to act_entry_point;

    These are the same actions you implemented in your polling loop,


What is a task?

  1. A set of instructions
  2. Current state, which is changed by executing instructions, which includes

Two tasks can use the same set of instructions, but

The kernel keeps track of every task's state

The TD normally contains

  1. The task's stack pointer, which points to a private stack, in the memory of the task, 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
  5. Links to queues on which the task is located

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

Kernel Structure

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

kernel( ) {
  initialize( );  // includes starting the first user task
    request = getNextRequest( );
    handle( request );

Where is the OS?

All the interesting stuff inside done by the kernel is hidden inside getNextRequest.

int getNextRequest( ) {
  return activate( schedule( ) ); //the active task doesn't change

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 a software interrupt

  1. Replace the instruction in main that calls func( ) to swi
  2. Replace the bx or mov pc, lr instruction that ends func( ) with mov pc, lr.

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 as the first thing done inside func( )
  3. Restore the context of main( ) from the stack jas the last thing done before the instruction that ends func( ).

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

To go beyond this we need to think about tasks more concretely

What we did here was to replace a function call with a software interrupt. Why bother?

  1. A software interrupt can leap tall barriers at a single bound
  2. A hardware interrupt is very similar to a software interrupt.

Return to: