CS452 - Real-Time Programming - Winter 2015
Lecture 10 - Name Server
Public Service Annoucements
- Due date for kernel 2: 30 January, 2015
- Updated k2.pdf
Inter-task Communication
Servers
What is a server?
- a task that provides service to a client task
- tasks requesting service, clients, must know the Tid of the
server
- a task that owns a resource and provides synchronized access to it.
- above,
- `a task' owns the interface
- other tasks may do the work
How are servers implemented?
We usually try to make each service simple, so the code of the
server that provides it is simple.
-
Receive is the key to how a server works.
- Receive a request
- Reply the response
-
There are two reasons why a server cannot send.
-
It does not know in advance which tasks will be its
clients, so it can't send to them to find out if they
require service.
-
If it sends in order to get resources it will remain blocked
for an unpredictable length of time, especially so if there is
a low priority task somewhere in the mix. If there is information it
needs it gets it by replying to a courier.
-
Sender (client, task that is making the request) blocks until
the response is available. That is, sender, in effect, is
running at the priority of the server between the request and
its reponse
-
Server priority should be set according to the importance
of the service it supplies, which depends on the importance
of the resource it controls.
-
But client priority should be considered by the server.
For example, a server might have
-
one execution path for higher priority client, and
-
a different execution path for lower priority client
-
The natural code for notifiers and servers usually
does the right thing.
-
You should be able to count on your clients to be
well-behaved.
A typical server has a lot in common with a warehouse
initialize;
FOREVER
Receive( *tid, request );
switch( request.type )
case PRODUCER:
if ( consumer-queued )
Reply ( dequeue( consumer ), request.content );
Reply ( producer );
break;
if ( space-available )
store( request.content );
Reply( producer );
break;
queue( producer );
case CONSUMER:
if ( producer-queued )
Reply ( consumer, content );
Reply ( dequeue( producer) )
break;
if ( content-available )
Reply( consumer, content );
break;
queue( consumer );
Name Server
What is a name server?
- There is a set of global execution-independent names
- There is a set of execution-dependent tasks that provide services
associated with the names
- Name server maintains an up-to-date table mapping names to resources
- Accepts requests to update the table
- Accepts queries concerning the table
Why Do We Need a Name Server
Names |
constant across applications
& executions |
interface |
Associated with a set of services (an API) |
Task Ids |
vary across applications
& executions |
implementation |
Associated with particular code
and data (an execution) |
How do You Get the Task Id of the Name Server?
Remember what you did when you were installing Linux?
- Make it a constant across executions.
- Is there any other way that's not disgusting.
Name Server API
int RegisterAs( char *name );
- One task can be registered under two names.
- Each name is associated with a single task.
- Name is
\000
terminated.
int WhoIs( char *name );
Name Server Semantics
RegisterAs
- Errors
- Not a legal name.
- It's up to you to decide what you will accept as legal
names
- tid is not a task
- tid is not the Name Server
- Already somebody registered with that name
WhoIs
- Errors
- Not a legal name.
- tid is not a task
- tid is not the Name Server
- No task registered under that name
Comments
RegisterAs
overwrites.
- Why? The rule is that the name -> task map is many to one.
- A task may have many names
- A name may have only one task
Analogy to Name Service on the Internet
- Every computer on the internet has an IP number (tid)
- Every computer that provides a service listens (receives) for its IP number
- The port is bound to the daemon providing the service when the daemon
is initialized
Name Server Implementation
What does the client need to know in order to use the name server
- its taskid
- the requests it services
- its API: function signatures and type definitions
User Pseudo-Code
First we need a struct for requests and reponses.
-
A structure for the request received by the name server
- Must be known by client
- It must be declared explicitly somewhere
struct NSmsg {
char name[MAXNAMESIZE];
int tid;
}
Using this struct send to the name server looks something like
Send( NSTid, (NSmsg *) msg, sizeof( NSmsg ), (NSmsg *) msg, sizeof ( NSmsg ) );
Name Server
- One service associates a taskid with a name
- The second service looks up the taskid and replys it to the
requestor
Questions
- How much will this code run?
- What should happen when a WhoIs request is made for an unregistered
name?
- How would you implement insert & lookup?
- Figure out
- What deadlines does Nameserver have?
- How many names will be in NameServer?
- How many RegisterAs? and when?
- How many WhoIs? and when?
- What should be allowable as a name?
Hardware Interrupts
What is a Hardware Interrupt?
In the CPU
- Test interrupt signal before fetching the next instruction
- actually AND of INT and the IRQ bit in the CPSR
- If asserted, change mode to IRQ
- Disable interrupt in CPSR
- Execute instruction at 0x18
In the Interrupt Control Unit (ICU)
- Several interrupts may be present when an interrupt occurs
- One is chosen, by a priority mechanism
- Put in a special place
- Software can choose to ignore priority mechanism in ICU
- Clearing one interrupt may just expose another one
In the Peripheral Hardware
- Several interrupts may be present
- ORed in peripheral hardware
- ORed in glue hardware
- Rare that there is a priority mechanism
- Clearing one interrupt can expose another one
When two interrupts are present
May have been two present when interrupt processing started
- in which case interrupt occurring now is known to be of lower
priority
May have occurred since interrupt processing started
- in which case interrupt occurring now may be of higher priority
What happens next?
- Kernel executes with interrupts disabled
- Context switch into user task turns on interrupts
- Before fetching the first user task instruction test interrupt
signal
- If asserted, re-initiate interrupt processing
Context Switches for Interrupts
Difference from Software Interrupts
It is impossible to predict where they occur
- You may have made some assumptions about when they occur
Assymmetry between User Task and Kernel
Scratch Registers must be saved
Two Link Registers
- One to return from interrupt
- In the registers of the interrupt handling code
- To return to the interrupted task in the right place
- One to move to the caller's stack frame
- In the registers of the interrupted task
- To return to whatever started in interrupted task
Helpful Features of the ICU
- Several places where you can read state
- Several places where you can block interrupt flow
- Trigger hardware interrupt from software
- What makes interrupts hard is that you are doing two semi-hard
things at once
- Making the hardware produce the interrupt
- Responding to the interrupt
- This allows you to separate them in developing/debugging
The Hardware in the Trains Lab
32-bit Timer
Base address: 0x80810080
Three registers:
Offset |
Function |
R/W |
Bits |
Comments |
0x0 |
Timer3Load |
R/W |
32: <Load/Reload Value> |
|
0x4 |
Timer3Value |
R |
32:<Current value> |
Set when Load is written,
even when counting |
0x8 |
Timer3Control |
R/W |
3:xxx<CLKSEL>xx<MODE><ENABLE> |
<CLKSEL>: 0, 2KHz clock; 1, 508KHz
<MODE>: 1, count continuously; 0, count once
<ENABLE>: Clock turned on
|
0xc |
Timer3Clear |
W |
32: |
Writing anything clears the interrupt |
Interrupt Control Unit (ICU)
The actual device is the ARM PL190
The logic in this design is completely asynchronous, so it functions when
the CPU clock is turned off.
- Important (= essential) for low power operation.
All input signals are
- active high
- level sensitive
Base addresses
- VIC1:
0x800B0000
- VIC2:
0
x800C0000
Basic Operation
VIC powers up with
- all vectored interrupts disabled.
- all interrupts masked
- all interrupts giving IRQ
Procedure
Initialization
- leave protection off
- enable in VICxIntEnable when you are ready to handle the interrupt
On an interrupt
- Read VICxIRQStatus
- Choose which interrupt you wish to handle
- Clear the interrupt source in the device
For debugging
- Use VICxSoftInt and VICxSoftIntClear to turn interrupt sources off and
on in software
Hardware Definitions
Registers for Basic Operation
Register Name |
Offset |
R/W |
Description |
VICxIRQStatus |
0x00 |
RO |
One bit for each interrupt source
1 if interrupt is asserted and enabled
|
VICxFIQStatus |
0x04 |
RO |
As above for FIQ |
VICxRawIntr |
0x08 |
RO |
As above but not masked |
VICxIntSelect |
0x0c |
R/W |
0: IRQ, 1: FIQ |
VICxIntEnable |
0x10 |
R/W |
0: Masked, 1: Enabled |
VICxIntEnClear |
0x14 |
WO |
Clears bits in VICxIntEnable |
VICxSoftInt |
0x18 |
R/W |
Asserts interrupt from software |
VICxSoftIntClear |
0x1c |
WO |
Clears interrupt from software |
VICxProtection |
0x20 |
R/W |
Bit 0 enables protection from user mode access |
VICxVectAddr |
0x30 |
R/W |
Enables priority hardware
See documentation.
|
Helpful Features of the ICU
- Several places where you can read state
- Several places where you can block interrupt flow
- Trigger hardware interrupt from softwareonce
- What makes interrupts hard is that you are doing two semi-hard
things at once
- Making the hardware produce the interrupt
- Responding to the interrupt
- Software interrupt generation allows you to separate them in
developing/debugging
Non-vectored Operation
Initialization
- Enable interrupt in device
- Enable interrupt in ICU
- Enable interrupt in CPU, usually by MOVS
Interrupt occurs
- AND of IRQ and NOT( IRQ disabled bit in CPSR ) is checked before each
instruction fetch.
- If set IRQ exception is taken in place of next instruction fetch.
- Possibly zero instructions of active task are executed.
- Make sure that this case works
- Context switch into kernel
Context switch novelties
Difference from Software Interrupts
- It is impossible to predict where they occur
- You may inadvertently have made some assumptions about when they
occur
- Scratch Registers must be saved
- r0-3
- IP -- used only very occasionally by gcc
- Two Link Registers
- One to return from interrupt
- One to return from the interrupted task to whatever called
it
- Turn off interrupt in device
- Should turn off interrupt in ICU
- What about IRQ?
You are now ready to process the interrupt in the kernel
Return to: