Homework 8 Solutions
22C:116, Spring 1997
Ioana M. Lungeanu
Problem 1 part A:
The body of the RPC Client Stub:
create(replyEntry, replyQueue);
send(requestBuf, requestLen, replyEntry, (1,1,1), remote);
receive(replyQueue, replyBuf, replyLen, replyCount, NULL);
Comments: The rights mask is (1,1,1) because:
- remote link must be reusable for the next request.
- reply link is transferable as a lnk parameter in send.
- reply entry is duplicatable since it follows a receive.
The RPC Server Stub:
create(remoteEntry, client);
broadcast the remoteEntry to the world
while(1) {
receive(client, requestBuf, requestLen, requestCount, replyEntry);
service(requestBuf, requestCount, replyBuf, replyLen);
send(replyBuf, replyLen, Null, (0,0,0), replyEntry);
}
Problem 1 part B:
First, the client sends the procedure id, the number in input
arguments m and the number of output arguments n. In the same
message, it sends the reply link.
Then, the server creates a new link for incomming parameters.
This new link is necessary because without it, the server could
not distinguish messages delivering parameters for one service
from messages on behalf of other clients. It sends to the client
this link, and the client sends the succession of arguments. If
the message queues are not really FIFO, each argument can be give
a serial number, or the server can prompt for successive arguments.
Then, the server calls the remote procedure and then sends return
arguments to the client. Again, if the message queues are not
FIFO, each reply message must have a serial number or the client
must prompt for each return argument.
The following solution uses prompting to sequence the arguments:
The body of the RPC Client Stub:
create(replyEntry, replyQueue);
send({procedureId, m, n}, len, replyEntry, (1,1,1), remote);
for(i=0; i<m; i++) {
receive(replyQueue, Null, 0, Null, paramIn);
send(argumentIn[i], len, replyEntry, (0,0,0), paramIn);
}
receive(replyQueue, Null, 0, Null, paramOut);
for(i=0; i<n; i++) {
send(Null, 0, replyEntry, (1,1,1), paramOut);
receive(replyQueue, argumentOut[i], len, count, Null);
}
The RPC Server Stub:
create(remoteEntry, client);
advertise remoteEntry to the world
while(1) {
receive(client, {procedureId, m, n}, len, count, replyEntry);
create(paramIn, paramInQueue);
for (i=0; i<m; i++) {
send(Null, 0, param, (1,1,1), replyEntry);
receive(paramQueue, argumentIn[i], len, count, Null);
}
service(procedureId, m, n, argumentIn, argumentOut);
create(paramOut, paramOutQueue);
send(Null, 0, paramOut, (1,1,1), replyEntry);
for (i=0; i<n; i++) {
receive(paramOutQueue, Null, 0, Null, Null);
send(argumentOut[i], len, Null, (0,0,0), replyEntry);
}
}
Problem 2:
The problem is how to make a non-blocking receive in the client,
because the client must wait for one of two messages: either
from the RPC server, either from the timr-server. This is solved
by using the same message queue for both links. Then, receive is
done on this shared queue. If the message contains no data, then
it is the timeout, so the request must be retransmitted. The
server keeps a flag for each request id, telling if the request
was serviced or not. When a request comes, it checks to see if it
is the original request or just a copy.
The body of the RPC Client Stub:
create(replyEntry, replyQueue);
create(timeoutEntry, replyQueue);
do {
send(requestBuf, requestLen, replyEntry, (1,1,1), remote);
send(delay, len, timeoutEntry, (1,1,1), timer);
receive(replyQueue, replyBuf, replyLen, count, NULL);
} while(count == 0);
The RPC Server Stub:
create(remoteEntry, client);
while(1) {
receive(client, requestBuf, requestLen, requestCount, replyEntry);
if (!serviced[requestBuf.requestId])
service(requestBuf, requestCount, replyBuf, replyLen);
send(replyBuf, replyLen, Null, (0,0,0), replyEntry);
}
Problem 3:
1 One server for each procedure:
This scheme is very fast because of the possibility to run different
procedures in parallel. However, if the procedures have side efects,
because they alter shared data, then race conditions occur, which are
unwnated. So, these scheme is very good if procedures don't share
data.
2 One server for all procedures:
This scheme is slower than the first because, only one procedure may
be executed at a time. But this eliminates the race conditions in the
case of shared data between procedures. There is no difference from the
shared data point of view between the scheme 2 and 3. Scheme 2 (with
a single queue) may be a little faster that scheme 3 (with multiple
queues), because the multi-receive primitive has to poll each queue,
and this takes time. However, scheme 3 may be easier to use, because
the procedure is specified by the queue number.
In effect, this forces the procedures to be run with implicit mutual
exclusion unless a multithreaded server is used.
3 Procedures represent methods of an object:
This is a clear example of data sharing. Scheme 2 and 3 are recommended,
because they eliminate race conditions. For objects with a single
server per object, mutual exclusion between methods becomes natural;
this is usually desirable and matches the semantics of Hoare's monitors.
If large numbers of small objects must be supported, this requires a
proliferation of servers!
Also, every time an object is created, a new RPC server would have to
be created if one server represents one object.
4 Procedures represent methods of a class of objects:
If one server supports all members of a class, object creation involves
a message to that server, and that server holds all objects of that class
inside itself. This is probably inappropriate for large objects, but if
large numbers of small objects are involved, it imposes a minimum
overhead per object.
Problem 4:
When a client calls a remote procedure in the server, for each
parameter b passed by name or by refence it sends to the server
two thunks: b_set() and b_get().
For each assignment to b in the remote procedure, the server
calls b_set() to be executed in the client, and for each evaluation
of b in the remote procedure, the server calls b_get() to be
executed in the client.
In other words, the client becomes an RPC server for the server,
providing for each parameter 2 procedures.