CS452 - Real-Time Programming - Spring 2012

Lecture 10 - Name Server

Public Service Annoucements

  1. Due date for assignment 1
  2. Next week's classes
  3. 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


int Send( Tid tid, char *message, int mslen, char *reply, int rplen )

These are pretty self explanatory, except

  1. The return value is the number of characters actually placed in the reply-buffer
  2. If something goes wrong, the return value is negative, coded to indicate what went wrong

    What can go wrong

    1. Illegal tid
    2. 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 Receives

  3. Parsing argument and reply-buffer is potentially costly and error-prone

Implementing Send

What's in user space is just stubs.

What the kernel must do

  1. Check arguments
  2. Change state of sender to RECEIVE_BLOCKED
  3. Put sender on the end of the receiver's sendQ
  4. If receiver is SEND_BLOCKED, do from #3 in Receive.

int Receive( Tid *tid, char *message, int msglen )

These are pretty self explanatory, except

  1. How is the task id copied form kernel to receiver?
  2. What if the buffer wasn't big enough?
  3. If several tasks have done Send, which one gets Received first?
  4. return value is number of bytes in message, including terminal character (\000) if the message is really a string..
  5. If something goes wrong, the return value is negative, coded to indicate what went wrong

    What can go wrong?

    1. 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

  1. Check arguments
  2. Change receiver's state to SEND_BLOCKED
  3. Check the sendQ
  4. If sendQ is empty
    1. exit from kernel after scheduling

    sendQ is not empty

    1. extract head of the send queue, called the sender below
    2. copy message from sender to receiver, after checking buffer sizes
    3. change sender's state to REPLY_BLOCKED
    4. change receiver's state to READY
    5. put sender's tid into receiver's argument
    6. put receiver on its readyQ
    7. set up receiver's return value
    8. exit from kernel after scheduling

int Reply( Tid tid, char *reply, int rplen )

These are pretty self explanatory, except

  1. The Replyer need not be the Receiver, but must be in contact with the Receiver
  2. When all goes well Reply leaves two tasks READY when it completes

Implementing Reply

  1. Check arguments
  2. Copy message from replier to sender, checking buffer sizes
  3. Set up sender's return value
  4. Change sender's state to READY
  5. Put sender on readyQ
  6. Set up replier's return value
  7. Change replier's state to READY
  8. Put replier on readyQ
  9. Exit from kernel after scheduling

Servers

What is a server?

How are servers implemented?


Name Server

What is a name server?

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?

  1. Make it a constant across executions

Name Server API

int RegisterAs( char *name );
int WhoIs( char *name );

Name Server Semantics

RegisterAs

WhoIs

Comments

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

  1. How much will this code run?
  2. How would you implement insert & lookup?

Return to: