CS452 - Real-Time Programming - Fall 2010
Lecture 4 - Tasks, Kernel
Pubilic Service Announcements
- Kernal 1 outline
- Kernel 1 Deadline
Kernel of a Real-time Operating System
Diagram
What Does the Kernel Provide
Tasks
- Provide applications with modularity, which is a higher level at which
they can be organized
- Consist of
- instructions, common to all tasks of the same kind
- global state, common to all tasks of the same kind
- local state, different state in different tasks of the same
kind
- How tasks work together
- synchronization
- communication
- combined into one mechanism: message passing
- Why are tasks important?
- Thinking about one thing at a time is easy.
- Thinking about coming to school this morning
- Thinking about more than one thing at a time is hard.
- Thinking about coming to school and listening to me talking
about coming to school
- While walking you may have been talking to somebody, or
thinking about something.
You did both effortlessly. How?
- Thinking about more than one thing at a time, in real-time, is very
hard
- Thinking about turning the wheel, peddling and balancing while
learning to ride a bicycle
- Tasks turn learing to ride a bicycle into thinking and walking.
Communication
Communication has two aspects
- sharing information, requesting service
- synchronization
We use Send/Receive/Reply (SRR) to do both.
- Send blocks
- Receive blocks: is synchronous with the call to send
- Reply doesn't block: is synchronous with the return from send
Synchronization
- Between tasks
- Coordination of execution in co-operating tasks
- Uses SRR
- With internal events
- Real-time by synchronizing with a real-time clock: e.g. clock
server
- Ordering execution: e.g. name server, bounded buffer
- Uses SRR
- With external events
Interrupts
Input from the outside world
- Provide the information you polled for
- ISR OS design
entry_point1 :
action1;
entry_point2:
action2;
...
entry_pointn:
actionn;
These are the same actions you implemented in your polling loop,
- and the have all the same problems.
- Somthing to think about
- Polling loop was single-threaded
- You were guaranteed not to be in the middle of a
computation when you got the signal to start another one.
- ISRs are not necessarily single-threaded
- You could get back the polling loop by turning off
interrupts during the action.
- No hierarchy of importance among ISRs
- Polling loop hierarchy was in the polling structure
- Selective interrupt masking can reproduce the
hierarchy,
- But then you have to save state
Kernel Structure
The kernel is just a function like any other, but which runs forever.
kernel( ) {
initialize( ); // including starting the first user task
FOREVER {
request = getNextRequest( );
handle( request );
}
}
Where is the OS?
- requests come from running user tasks
- one type of request creates a task
- There needs to be a first task that gets everything going
Tasks
What is a task?
- A set of instructions
- Current state, which is changed by executing instructions
- values of its variables, which are automatic variables maintained
on the stack
- contents of its registers
- other processor state such as the PSR
- processor mode
- condition codes
- etc.
- its run state and other things maintained by the kernel
Two tasks can use the same set of instructions, but
- every task has its own state
- Therefore, no static variables
The kernel keeps track of every task's state
- In essence, servicing a request amounts to changing the state of one or
more 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
- The task's stack pointer, which points to a private stack, in the
memory of the task, containing
- PC
- other registers
- local variables
all ready to be reloaded whenever the task next runs.
- Possibly the return value for when the task is next activated
- The task's parent
- The task's state
- Links to queues on which the task is located
- The kernel uses these to find the task when it is ervicing a
request
Possible states of the task
- Active: running or about to run
- On a single processor system only one task can ever be active.
- Ready: can run if scheduled
- Need a queue used by the scheduler when deciding which task should
be the next active task
- Blocked: waiting for something to happen
- Need several queues, one for each thing that could happen
All the interesting stuff inside done by the kernel is hidden inside
getNextRequest
.
int getNextRequest( active ) {
nextRequest = activate( active ); //the active task doesn't change
return nextRequest;
}
What's inside activate( active )
?
- transfer of control to the active task
- execution to completion of the active task
- `to completion' means until the active task sends a request to the
kernel
- transfer of control back to the kernel
- getting the request
The hard part to get right is `transfer of control'
- which we call a context switch
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" );
}
- Compile and run it.
- 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?
- Add to the assembly code a line that puts the address of the first
instruction of
func( )
into the interrupt vector
- Compile the assembly code and run it.
3. Change to calling func(
) using a software interrupt
- Replace the instruction in main that calls func( ) to
swi
n
- 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.
- Add stuff to
main( )
so that it has context
- Save the context of
main( )
on the stack as the first
thing done inside func( )
- 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?
- A software interrupt can leap tall barriers at a single bound
- A hardware interrupt is very similar to a software interrupt.
Return to: