CS452 - Real-Time Programming - Fall 2008
Lecture 11 - Send/Receive/Reply
Questions & Comments
Producer/Consumer
Two ways to do this
- Producer
Sends, consumer
Receives
Send means "Here is some data"
Receive means "I'm ready to receive data"
Reply means "I got the data"
After Reply buffers holding data can be overwritten at
will
- Producer
Receives and Replys
Send means "I'm ready for data"
Receive means "I'm ready to transmit data"
Reply means "Here's the data"
After Reply buffers can be overwritten at will.
What is the difference?
- If relationship is one-to-one
- If relationship is many-to-one
- the one doing many MUST
Receive.
- If relationship is many-to-many
- there must be an extra component that Receives from both
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
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
Sended, which one gets
Received first?
- return value is number of bytes in message, including \0.
Implementing Receive
What the kernel must do
- Check the sendQ
- If SENDQ_EMPTY
- change state to SEND_BLOCKED
- Wait for Send
- 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 variable
- put receiver on 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.
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: