CS452 - Real-Time Programming - Spring 2009
Lecture 12 - Send/Receive/Reply
Reminders
Practical Details
- Need to keep around request
- Messages
- Typed as strings
- requires formatting and parsing
- Normally cast from pointers to structs
- struct expected by receiver/sender must agree with struct
provided by sender/receiver
- Type-checking by compiler not possible
- Dynamic type-checking possible
- First element of struct is its type
- Even polymorphism is possible
- Message types should be handled in a more modern way
- type extension
- would provide a more uniform handling of error returns
- Task states
- DEFUNCT is terminal
- READY -> ACTIVE
- ACTIVE -> SEND_BLOCKED, RECEIVE_BLOCKED, READY, DEFUNCT
- SEND_BLOCKED -> READY
- RECEIVE_BLOCKED -> REPLY_BLOCKED
- REPLY_BLOCKED -> READY
- You can add extra return values beyond those specified
int Send( Tid tid, char *arg, int arg-length, char *reply-buffer, int
reply-buffer-size )
These are pretty self explanatory, except
- The return value is the number of characters actually placed in the
reply-buffer
- including the \0 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
Receives
- 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
- This form of message passing requires user and kernel code to cooperate
to avoid malignancies
- which is just barely okay when one implementer does both
- but is otherwise monumentally insecure
Implementing Send
What's in application 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 receiver's sendQ
- If receiver is SEND_BLOCKED, do 3 in receiver
- Wait for Reply
int Receive( Tid *tid, char *arg-buffer, int arg-buffer-length )
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
Received first?
- return value is number of bytes in message, including \0.
- 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 Send to check that the reply-buffer was big
enough by looking at its return value
Implementing Receive
What the kernel must do
- Check the
sendQ
- If SENDQ_EMPTY
- change state to SEND_BLOCKED
- Exit from kernel after scheduling
sendQ is not empty
sender = head( sendQ )
sendQ = next( sendQ )
- copy message from sender to receiver, after checking buffer
sizes
- change sender's state to REPLY_BLOCKED
- put sender's tid into receiver's argument
- put receiver on its
readyQ
- set up receiver's return value
- change receiver's state to READY
int Reply( Tid tid, char *reply, int reply-length )
These are pretty self explanatory, except
- The Replyer need not be the Receiver, but must be in contact with the
Receiver
Implementing Reply
- Check arguments
- sender (tid) must be REPLY_BLOCKED
- Copy message from replier to sender, checking buffer sizes
- Put sender on readyQ
- Set up sender's return value
- Change sender's state to READY
- Put replier on readyQ
Set up replier's return value
replier 's state is already ready
Return to: