CS452 - Real-Time Programming - Spring 2012
Lecture 10 - Name Server
Public Service Annoucements
- Due date for assignment 1
- Next week's classes
- Assignment 2
Send/Receive/Reply
Sequence of States
There are two cases
Send before Receive
Sender
Action
|
Sender
State
|
Receiver
Action
|
Receiver
State
|
Comments |
|
active |
|
|
|
Send |
RCV_BL |
|
|
sender added to receiver's sendQ |
|
|
|
active |
|
|
RPL_BL |
Receive |
ready |
request copied
sender deleted from receiver's sendQ
|
|
|
|
active |
service performed |
|
ready |
Reply |
ready |
reply copied |
Receive before Send
Sender
Action
|
Sender
State
|
Receiver
Action
|
Receiver
State
|
Comments |
|
|
|
active |
|
|
|
Receive |
SND_BL |
receiver's sendQ empty |
|
active |
|
|
|
Send |
RPL_BL |
|
ready |
request copied |
|
|
|
active |
service perfomed |
|
ready |
Reply |
ready |
reply copied |
Practical Details
- Need to keep around request
- For Send_Blocked receivers in the SendQ
- The same as Receive_Blocked senders
- For Reply_Blocked senders.
- Messages
- Task states
- You can add extra return values beyond those specified
int Send( Tid tid, char *message, int mslen, char *reply, int rplen )
These are pretty self explanatory, except
- The return value is the number of characters actually placed in the
reply-buffer
- including the terminal character ( \000 ) if the contents of the
reply buffer is a string
- If something goes wrong, the return value is negative, coded to
indicate what went wrong
What can go wrong
- Illegal
tid
tid
not an existing task
It's up to Send
to check that the reply-buffer was big
enough by looking at its return value
It's not an error if the task to which we Send
never
Receive
s
- Should it be?
- Hint. Finding out if a task "never Receives" is equivalent to what
problem?
- Parsing
argument
and reply-buffer
is
potentially costly and error-prone
- A type system might be nice
- But then you would feel compelled to implement run-time type
checking
Implementing Send
What's in user space is just stubs.
- checking arguments
- putting arguments in the right place
- Note that there are five arguments
What the kernel must do
- Check arguments
- Change state of sender to RECEIVE_BLOCKED
- Put sender on the end of the receiver's sendQ
- If receiver is SEND_BLOCKED, do from #3 in
Receive.
int Receive( Tid *tid, char *message, int msglen )
These are pretty self explanatory, except
- How is the task id copied form kernel to receiver?
- That is, where does the pointer point to?
- What if the buffer wasn't big enough?
- If several tasks have done
Send
, which one gets
Receive
d first?
- return value is number of bytes in message, including terminal
character (\000) if the message is really a string..
- It seems as though the return value should be the tid. Something is
not right.
- If something goes wrong, the return value is negative, coded to
indicate what went wrong
What can go wrong?
- Only part of the message was copied
It's up to Receive
to check that the message-buffer was
big enough by looking at its return value
Implementing Receive
What the kernel must do
- Check arguments
- Change receiver's state to SEND_BLOCKED
- Check the
sendQ
- If sendQ is empty
- exit from kernel after scheduling
sendQ is not empty
- extract head of the send queue, called the sender below
- copy message from sender to receiver, after checking buffer
sizes
- change sender's state to REPLY_BLOCKED
- change receiver's state to READY
- put sender's tid into receiver's argument
- put receiver on its
readyQ
- set up receiver's return value
- exit from kernel after scheduling
int Reply( Tid tid, char *reply, int rplen )
These are pretty self explanatory, except
- The Replyer need not be the Receiver, but must be in contact with the
Receiver
- When all goes well Reply leaves two tasks READY when it completes
Implementing Reply
- Check arguments
- sender (tid) must be REPLY_BLOCKED
- Copy message from replier to sender, checking buffer sizes
- Set up sender's return value
- Change sender's state to READY
- Put sender on readyQ
- Set up replier's return value
- Change replier's state to READY
- Put replier on readyQ
- Exit from kernel after scheduling
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?
- Receive is the key
- Receive a request
- Reply the response
- 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.
- But client priority should be considered by the server. For
example,
- One set of instructions for higher priority client
- One set of instructions for lower priority client
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 a particular set of instructions and data (an
execution) |
How do You Get the Task Id of the Name Server?
- Make it a constant across executions
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
Name Server Implementation
User Code
E.g., RegisterAs
typedef struct {
int type;
char name[MaxNameSize];
int tid;
} NSstruct;
int RegisterAs( char *name ) {
NSstruct *req, *result;
bytes = Send( NSTid, (char *) req, sizeof(NSstruct), (char *) result, sizeof(NSstruct) );
if ( bytes != sizeof(NSstruct) ) {
// Do something error-like
} else return 0;
}
There are lots of possible variations.
Server Code
typedef struct {
int type;
char name[MaxNameSize];
int tid;
} NSstruct;
NSstruct req;
// initialize tables
FOREVER {
bytes = Receive( &tid, &req, sizeof(NSstruct) );
if ( detectError( ... ) ) {
// Reply with error
} else {
switch( req.type ) {
case REGISTERAS:
insert( req.name, tid );
Reply( tid, SUCCESS, sizeof(NSstruct) );
break;
case WHOIS:
result.tid = lookup( name );
Reply( tid, result, sizeof(NSstruct) );
break;
default: // This should never happen
Reply( tid, ERROR, sizeof(int) );
break;
}
}
}
Comments
- How much will this code run?
- 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?
Return to: