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