CS452 - Real-Time Programming - Spring 2013
Send/Receive/Reply
Pubilc Service Annoucements
- Due date for kernel 2: 31 May.
Inter-task Communication
Overview
Message passing combines synchronization and communication in one set of
primitives.
int Send( Tid tid, char *message, int mslen, char *reply, int rplen )
- blocks until Reply occurs
int Receive( Tid *tid, char *msg, int msglen )
- blocks until message is available
- Only one waiting sender is processed per Receive
- Why?
- Hint. There might be tasks that are higher priority than the
Receiver.
int Reply( Tid tid, char *rply, int rplylen )
- does not block
- unblocks task that called Send
Send and Reply become READY at the same time.
How are They Used?
The Producer/Consumer Problem
Middle (double) arrow shows the direction that information flows.
+--------------+ +--------------+
| | ---> | |
| Producer | ===> | Consumer |
| | <--- | |
+--------------+ +--------------+
Producer Sends
Upper arrow
- Producer sends and blocks: "I have some XXX for you."
- Consumer receives: "Give me some XXX."
- Consumer accepts XXX.
- Consumer replies: "I got the XXX."
- Producer & consumer are simultaneously READY.
Note. 1 & 2 could be run in the opposite order.
Consumer Sends
Lower arrow
- Consumer sends and blocks: "I am ready for some XXX from you."
- Producer receives: "I have some XXX."
- Producer replies: "Here is the XXX."
- Consumer accepts XXX.
- Producer and consumer are simultaneously READY.
Note. 1 & 2 could be run in the opposite order.
Multiple Producers
Producers send; consumer receives in the order that producers send.
Notes.
- Critical races can occur, which the application programmer must
resolve.
- There are two types of critical race.
- Critical races internal to the application. For example, order of
production changes in one producer because you add or remove a printf
statement. These ones you can program out of existence by changing
priorities, communication patterns, etc.
- Ones external to the application. For example, one producer is
forwarding bytes from the keyboard, the other from the train
controller, and the order of production changes because the user
types a little faster. These ones you cannot program out of
existence, but must program so that the right thing happens
regardless of the order of production.
Multiple Consumers
Consumers send; producer receives in the order that consumers send.
Note. Critical races can occur, which the application programmer must
resolve.
Multiple Consumers AND Multiple Producers
Consumers send and producers send: who receives?
- A third task: you call it a FIFO or buffer; I call it a warehouse
+---------------+ +------------+ +---------------+
| | ---> | | <--- | |
| Producers | ===> | Buffer | ===> | Consumers |
| | | | | |
+---------------+ +------------+ +---------------+
Buffer receives two types of request
- Producer: Here is some XXX
Send( warehouse, accept some XXX, ... )
- Warehouse receives
Receive( *producer, XXX )
- Warehouse stores XXX, replies
insert( XXX, shelf );
Reply( producer, ack 1 XXX, )
- If warehouse is full of XXX two strategies are possible
- Warehouse queues producer, who remains Reply_Blocked until
there is space created in the warehouse
- Warehouse replies with refusal
Reply( producer, can't take XXX, )
The second strategy is considered to be not so good. Why?
- Consumer: I want some YYY
Send( warehouse, want some YYY, ... )
- Warehouse receives, gets YYY
Receive( &consumer, YYY )
- Warehouse replies, providing YYY
extract( YYY, shelf);
Reply( consumer, YYY )
- If warehouse is empty of YYY, two strategies are possible
- Warehouse queues sender, who remains Reply_Blocked
- Warehouse replies with refusal
Reply( consumer, all out of YYY, )
Notes.
- Only a receiver can accept two types of requests at once. The buffer,
which only receives is the simplest example of a server.
- Messages in Send/Receive/Reply must be the same 'type'.
Sequence of States
Sender
- Active -> Receive_Blocked
- Receive_Blocked -> Reply_Blocked
- May happen right away
- When Receive is called with the Receiver's SendQ empty
- Otherwise, when Receive is called
- Reply_Blocked -> Ready
Receiver
- Active -> Send_Blocked
- Send_Blocked -> Ready
- May happen right away
- if the sendQ is not empty
- Ready -> Active
- ...
- Active -> Ready
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
- Keeping around the request
- Send before Receive
- request is a pointer into the sender's address space
- sender is still blocked when copying occurs
- request is copied from sender's address space into receiver's
address space by kernel while receive is being handled.
- Receive before Send
- request will be copied to a pointer into the receiver's address
space
- receiver remains blocked until send occurs
- request is copied from sender's address space into receiver's
address space by kernel while send is being handled.
- Reply
- response is a pointer into the replier's address space
- sender is still blocked when copying occurs
- response is copied from replier's address space into sender's
address space by kernel while reply is being handled.
- Copying inside the kernel is the reason why you want
- unformatted messages
- fast memcpy
- Messages
- Task states
- You can add extra return values beyond those specified
Example of a Difficult Bug
You notice that
- Tasks that are RCV_BL are never on ReadyQs.
- The next pointer is available to link the Receiver's sendQ.
Your reasoning is based on the following scenario.
- Sender calls Send while receiver is RDY.
- Sender is placed on receiver's SendQ.
- A second sender calls Send before first sender has been received.
- The second sender is put on the first sender's next pointer.
- As many more as you like.
- Receiver calls Receive and immediately has a transaction with first
sender.
- removing the first sender from the SendQ pulls the second sender
onto it.
- Receiver calls Reply; both receiver and first sender are RDY.
- first sender's next pointer is available for use in ReadyQ.
- Receiver runs first, calls Receive and handles second sender
Return to: