CS452 - Real-Time Programming - Winter 2015
Lecture 4 - Tasks & Kernels
Public Service Annoucements
- Marking of a0.
- Due date for kernel 1: 26 January, 2015
Kernel of a Real-time Operating System
Introduction
In the next few weeks we will build, from scratch, a micro-kernel.
The micro-kernel supervises the execution of tasks, which are the
elements of our systems. (A task is a function with no arguments
and no return value.)
The base unit of a polling loop is
This looks more than you think like the operating systems to which
you are accustomed. The actions you used in assignment zero
responded to hardware events detected by execution of a condition.
Walking before we try to run we respond to hardware events in
part 3 of the kernel.
The code that implements an action needs support. It must
- execute instructions
- code with the pc pointing into it
- state, in the form of memory
- communicate
- transfer data
- synchronize
- receive/send information from/to the outside world
- provide data
- possibly nothing but synchronization
These basic needs are provided by the kernel of an operating
system. The kernel we create in cs452 is a microkernel, because it
provides these capabilities and nothing more.
We build the microkernel in four assignments
- task creation and scheduling
- inter-task communication
- the interrupt primitive
- complex servers
The real-time operating system we build consists of
-
an uninterruptible microkernel, plus
-
interruptible device-handling server tasks that run in user-space
What Does a Microkernel Provide?
Tasks
A program is conceived as a collection of co-operating tasks. Tasks
provide applications with modularity. Task structure as a method
of program organization will be discussed about the time you are
finishing the OS.
Tasks consist of
- instructions, common to all tasks of the same kind,
- global constants, such as strings used for formatting messages, and
- local state, different state in different tasks of the same kind, which requires a separate block of memory for each instantiation of a task..
Why are tasks important?
- Thinking about one thing at a time is easy.
- Consider the jobs you might get after you graduate.
-
Thinking about more than one thing at a time is hard.
- Keep on thinking, and at the same time listen to me talking
about tasks
-
Thinking about more than one thing at a time, in real-time, is very hard
-
jhink about turning the wheel, peddling and balancing
while learning to ride a bicycle
-
How did you learn to coordinate all these activities
in real-time?
-
Tasks allow a programmer to reduce parts of a activity into
sequences of instructions that communicate with other
sequences.
Communication
Communication has two aspects
- sharing information and
- 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
Sharing data
Data is usually shared in the form of a struct
,
which requires a common name space of types, but removes parsing
and formating.
Send does transfers both ways at once. Receive and Reply
transfer one way each.
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
In the polling loop you polled a register
-
to discover if input had arrived
-
to discover if you could send output
Almost every test failed, which wastes CPU. Even worse, it increases
the response time, the time from when the event occurs until the
first instruction of user code responding to it occurs.
You can get rid of the polling tests if you program the hardware
to send the CPU a signal when the condition for which you are
waiting occurs. Such a signal is called an exception and the CPU
goes into a privileged state when the interrupt occurs.
The kernel responds to the exception by reading volatile data and
readying the task that is waiting on the interrupt. This task is
essentially the action that was conditioned on the event in the
polling loop.
Tasks
What is a task?
- A set of instructions
-
The current state, which is changed by executing instructions.
The state of a task includes which includes
-
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 servicing 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.
- But we would like to generalize smoothly to more than one
processor.
- 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
Kernel Structure
The kernel is just a function like any other, but which runs forever.
void kernel( ) {
TD* = active;
initialize( ); // includes starting the first user task
FOREVER {
handle( getNextRequest( ) );
}
}
Where is the OS?
- a small function called
main( )
- initialized immediately after
main( )
is called
- starts the first user task
- entered from user tasks by SWI
- requests come from running user tasks
- one type of request creates a task
- There needs to be a first task that gets everything going
All the interesting stuff inside done by the kernel is hidden inside
getNextRequest
.
int getNextRequest( ) {
return activate( active = schedule( ) ); //the active task changes only here
}
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, OR
- until an interrupt occurs.
- 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
The Hardware/Software Provided in the Undergraduate Environment
Software provided and maintained by CSCF
TS-7200
Specific documentation from Technologic
System on Chip (SoC)
EP9302, designed and manufactured by Cirrus semiconductor
Memory
Byte addressable, word size 32 bits
Hardware configuration created by RedBoot
- 32 Mbytes of RAM, starting at
0x00000000
- 4 Mbytes of flash RAM, starting at
0x60000000
- Contains RedBoot, which is loaded into RAM on reset
- Special locations at low addresses
- interrupt vectors
- memory management tables
- Special locations above
0x80000000
Two types of special location
- Supplied by Technologic:
0x80840000
to
0x80840047
- Suppied by Cirrus:
0x80010000
to 0x8081ffff
0x808a0000
to 0x80900023
Separate instruction and data caches
`COM' ports
Connected to two UARTs implemented on the SoC
- RS-232
- Actual UART hardware is on the EP9302
- Really only two, stay away from what looks the third one, which is
probably only there to work around a bug in the SoC.
Reset switch
- red, even though documentation says black
- actually, some are black
EP-9302
Specific documentation from Cirrus
System on chip
ARM 920T core
Specific documentation from ARM, which covers
- ARM v4T instruction set
- 32 bit word, 32 bit bus
- all instructions one word
- except thumb instructions (T suffix), which you shouldn't
use
- in-order instruction issue
- some instructions privileged
- Only one instruction that lets you into privileged state: SWI --
software interrupt
- Core includes
- CPU
- MMU
- L1 cache
- Co-processor interface
- System control co-processor
Return to: