Async Receive Return control before have filled in msg variable with received messages. How can this be useful? Wait syscall (until msg avail) Test syscall (has msg arrived) Condition receive (receive or announce no msg yet) interrupt none are beautiful Timeouts If have blocking primitive, send or receive could wait forever. Some systems/languages offer timeouts. HOMEWORK 10.3 To buffer or not to buffer (unbuffered) If unbuffered, the received tells where to put the msg Doesn't work if async send is before receive (where put msg). For buffered, the kernel keeps the msg (in a MAILBOX) until the receiver asks for it. Raises buffer management questions HOMEWORK 10.5 Acks Can assert msg delivery are not reliable Checked at higher level Kernel can ack every msg Senders and repliers keep msg until receive ack Kernel can use reply to ack every request but explicitly ack replies Kernel can use reply as ack to every request but NOT ack replies Client will resend request Not always good (if server had to work hard to calculate reply) Kernel at server end can deliver request and send ack if reply nor forthcoming soon enough. Again can either ack reply or not. Large design space. Several multiway choices for acks, buffers, ... Click for diagram in postscript or html.
Other messages (meta messages??)
Are you alive?
I am alive
I am not alive (joke)
Mailbox full
No process listening on this port
---------------- Remote Procedure Call (RPC) ----------------
Birrell and Nelson (1984)
Recall how different the client code for copying a file was from
normal centralized (uniprocessor) code.
Lets make client server request-reply look like a normal procedure
call and return.
Tanenbaum says C has call-by-value and call-by-reference. I don't
like this. In C you pass pointers by value (at least for scalars) and
I don't consider that the same. But "this is not a programming
languages course"
HOMEWORK 10.7
Recall that getchar in the centralized version turns into a read
syscall (I know about buffering). The following is for unix
Read looks like a normal procedure to its caller.
Read is a USER mode program (needs some assembler code)
Read plays around with registers and then does a poof (trap)
After the poof, the kernel plays with regs and then does a
C-language routine and lots gets done (drivers, disks, etc)
After the I/O the process get unblocked, the kernel read plays
with regs, and does an unpoof. The user mode read plays with regs
and returns to the original caller
Lets do something similar with request reply
User (client) does subroutine call to getchar (or read)
Client knows nothing about messages
We link in a user mode program called the client stub (analogous
to the user mode read above).
Takes the parameters to read and converts it to a msg
(MARSHALLS the arguments)
Sends a msg to machine containing the server directed to a
SERVER STUB
Does a blocking receive (of the reply msg)
Server stub is linked with the server.
Receives the msg from the client stub.
Unmarshalls the arguments and calls the server (as a
subroutine)
The server procedure does what it does and returns (to the server
stub)
Server kows nothing about messages
Server stub now converts this to a reply msg sent to the client
stub
Marshalls the arguments
Client stub unblocks and receives the reply
Unmarshalls the arguments
RETURNS to the client
Client believes (correctly) that the routine it calls has returned
just like a normal procedure does.
Heterogeneity: Machines have different data formats
Previously discussed
Have conversions between all posibilities
Done during marshalling and unmarshalling
Adopt a std and convert to/from it.
HOMEWORK 10.8
Pointers
Avoid them for RPC!
Can put the object pointed to into the msg itself (assuming you
know its length).
Convert call-by-ref to copyin/copyout
If have in or out param (instead of in out) can elim one of
the copies
Gummy up the server to handle pointers special
Callback to client stub
Ugh
Registering and name servers
As we said before can use a name server.
This permits the server to move
deregister from the name server
move
reregister
Sometimes called dynamic binding
Client stub calls name server (binder) first time to get a HANDLE
to use for the future
Callback from binder to client stub if server deregisters or
have the attempt to used the handle fail so client stub will
goto to binder again.
HOMEWORK 10.12
Failures
This gets hard and ugly
Can't find the server.
Need some sort of out-of-band response from client stub to
client
Ada exceptions
C signals
Multithread the CLIENT and start the "exception" thread
Loses transparancy (centralized systems don't have this).
Lost request msg
This is easy if known. That is, if sure request was lost.
Also easy if idempotent and think might be lost.
Simply retransmit request
Assumes the client still knows the request
Lost reply msg
If it is known the reply was lost, have server retransmit
Assumes the server still has the reply
How long should the server hold the reply
Wait forever for the reply to be ack'ed--NO
Discard after "enough" time
Discard after receive another request from this client
Ask the client if the reply was received
Keep resending reply
What if not sure of whether lost request or reply?
If server stateless, it doesn't know and client can't tell.
If idempotent, simply retransmit the request
What if not idempotent and can't tell if lost request or reply?
Use sequence numbers so server can tell that this is a new
request not a retransmission of a request it has already done.
Doesn't work for stateless servers
HOMEWORK 10.13 10.14 Remind me to discuss these two next time
Server crashes
Did it crash before or after doing some nonidempotent action?
Can't tell from messages.
For databases, get idea of transactions and commits.
This really does solve the problem but is not cheap.
Fairly easy to get "at least once" (try request again if timer
expires) or "at most once (give up if timer expires)"
semantics. Hard to get "exactly once" without transactions.
To be more precise. A tranaction either happens exactly
one or not at all (sounds like at most once) AND the
client knows which.
Client crashes
Orphan computations exist.
Again transactions work but are expensive
Can have rebooted client start another epoch and all
computations of previous epoch are killed and clients
resubmit.
Better is to let continue old computations with owners
that can be found.
Not wonderful
Orhpan may hold locks or might have done something not
easily undone.
Serious programming needed.
Implementation
Protocol choice
Existing ones like UDP are designed for harder (more general)
cases so are not efficient.
Often developers of distributed systems, invent their own
protocol that is more efficient.
But of course they are all different.
On a lan would like large messages since they are more
efficient and don't take so long considering the high
datarate.
HOMEWORK 10.15