CS452 - Real-Time Programming - Winter 2015

Lecture 12 - AwaitEvent, Clock Server

Pubilc Service Annoucements

  1. Due date for kernel 3: 9 February, 2015.

Last gasp of the hardware context switch

In Lecture 11 we discussed the IP bug, which results in one task's instructions getting a different task's data. There is a dual bug, the LR bug, in which one task's data gets another task's instructions. Here is a sequence that produces it.

  1. A hardware interrupt occurs.
  2. The registers of the interrupted task are pushed onto its stack.
  3. The lr_IRQ overwrites the lr on the stack.
  4. When the interrupted task is next scheduled, registers r0-r14 are restored in system mode.
  5. Then, movs pc, lr restarts execution of the interrupted task.
This almost always works, but very infrequently it crashes. Why?

AwaitEvent

The final Kernel Primitive

... except for Destroy

int AwaitEvent( int eventType )

More About AwaitEvent

Argument

  1. Somewhere there is a list of event types
  2. This is not very portable

Processing in the kernel

Clock Server, Task Structure

How is AwaitEvent Used?

  1. There should (almost) always be a task blocked on AwaitEvent for every interrupt type. Why?
  2. A server cannot call AwaitEvent. Why?
  3. We call the task that calls AwaitEvent a Notifier. Why?
  4. Code for a typical Notifier
    struct delivery {
        int type;
        int data;
    }
    
    void notifier( ) {
        struct delivery request;
        // Initialization, probably including device
        // Synchronization
        FOREVER {
            request.data = AwaitEvent( evtType );
            request.type = NOTIFIER;
            Send( server, &request, ... );
        }
    }
  5. Code for a typical server
    void server( ) {
        struct delivery request;
        // create notifier
        // other initialization
        // synchronization
        FOREVER {
            Receive( &requester, &request, ... );
            switch ( request.type ) {
            case NOTIFIER:
                Reply( notifier );
                data = request.data;
                // use data
            case CLIENT:
                ...
            }
        }
    }

HALT versus an Idle Task

What do you do when there are no tasks to run?


Clock Server

Primitives

int Time( )
int Delay( int ticks )
int DelayUntil( int ticks )

Pseudo-implementation

void clock( ) {
    // Create Notifier and send  any initialization data
    // Initialize self
    FOREVER {
        Receive( &requester, &request, ... );
        switch ( request.type ) {
        case NOTIFIER:
            Reply( notifier, ... )
            // update time
        case TIME_REQUEST:
            Reply( requester, time,... )
        case DELAY_REQUEST: 
            // Add requester to list of suspended tasks
        }
        // Reply to any timed-out tasks
    }
}

Comments:

  1. You need a common request type, or possibly a union.
  2. You should notice a typical server pattern.

It's normal to sort the list of suspended tasks. Why?


Return to: