CS452 - Real-Time Programming - Spring 2016

Lecture 7a - Create (continued)

Public Service Annoucements

  1. Due date for kernel 1: 27 May, 2016
  2. Opening the trains lab on 28 May.
  3. There are three link registers
    1. The kernel's link register: to return from activate.
    2. The user task's link register (in the kernel) : to return from SWI.
    3. The user task's link register: to return from Create, or any other system call.
    In this part of the kernel you can make many link register bugs that have no symptoms now, but will later.
  4. Implementing a ready queue.
  5. Passing arguments to system calls. My rule of thumb is: You may be right and your compiler wrong about how best to pass arguments; all the same, if you choose to fight with your compiler it will almost always win.
  6. The frame pointer. During the context switch one frame pointer is overwritten by another. There you lose the ability to access one set of auto variables and start being able to access another set. (Something to check.)
  7. Optimization. O2 breaks some kernels; O3 breaks many kernels. It's not important, as we will see in part 2 of the kernel.

Creating a Task

In creating a task you have to do two things

  1. Get and initialize resources needed by the task
  2. Make the task look as if it had just entered the kernel

Things you need to do

Get an unused TD and memory for its stack. To do this you must decide what will be the maximum number of tasks in your system, and how you want to allocate the available memory among them.

A few implementation details.

Most of the work in creating a task fill in fields in the TD.

  1. task id
  2. stack pointer
  3. SPSR.
    Forgetting to save this, or doing it incorrectly is unlikely to crash kernel 1. But it's worth getting right because it can cause hard to fix bugs later in the course.
  4. Link register
    Remember that there are two user-space link registers: the one the kernel uses when it's time to restart the task that called Create, the other the one that is used to return from the Create function.
  5. Parent tid
  6. return value
  7. State, which is READY
  8. Priority, needed to install the task into its ready queue

Must also initialize the stack

The following implementation decisions are up to you.

Initializing the Kernel

Set up the Hardware

RedBoot gives you the processor with

Then there are a few things you need to do. While RedBoot gives you the system as described above, there may be things done by a previous student that changed what RedBoot thinks it is giving you.
  1. Initialize busy-wait I/O.
  2. Initialize low memory.
  3. Turn off interrupts in the ICU etc.
  4. As a debugging aid I sometimes put distinct bit patterns in the registers in order to get some easy information about what is going where.

Prepare the Kernel Data Structures

Where is the kernel's stack pointer, right now? What does the stack look like?

The kernel data structures. At the very least you need

  1. an array of empty ready queues
  2. a pointer to the TD of the active task
  3. an array of TDs
  4. a free list of pointers to free TDs. This might take the form of bits set in a couple of words.

Prepare the Memory to be Used by Tasks

  1. task memory

Create the First User Task

Can run with hardware interrupts turned off for now. But when hardware interrupts are turned on in kernel 3 interrupts in user tasks must be turned on, though they stay off in the kernel.

Reminder. The place where the kernel starts executing has the global name main, which cannot be re-used.

Other Primitives

These primitives exist mostly so that we, which includes you, can ensure that task creation and scheduling are working when there is not much else implemented.

Tid MyTid( )


A question, to which there is a correct answer, or more specifically, a correct (answer, reason) pair.

Tid MyParentTid( )


Where is the parent Tid, and how does the kernel find it?

void Pass( )

Doesn't block: task calling Pass( ) makes a state transition from ACTIVE to READY.

Does reschedule.

When is Pass( ) a NOP?

void Exit( )

Calling task is removed from all queues, but its resources are not reclaimed or reused.

That is, the task goes into a zombie state, and will never become active or ready, but continues to own all its resources.

Return to: