[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
synchronous RPCs vs. asynchronous RPCs
From: |
Marcus Brinkmann |
Subject: |
synchronous RPCs vs. asynchronous RPCs |
Date: |
Fri, 5 Sep 2003 01:44:52 +0200 |
User-agent: |
Mutt/1.5.4i |
Hi,
here is food for thought.
Heretic claim of the day:
"We should only do synchronous RPCs, and implement all asynchronous RPCs as
synchronous RPCs performed by a helper thread."
This applies to select()/poll(), asynchronous msync() and other operations
like that. I don't think it should apply to notifications like task death
notifications (although... I am still considering it! If we can restrict it
to task death notifications, we only need one thread. Object death
notifications for other capabilities can (from the servers point of view)
safely deferred until the client actually tries to use the capability the
next time - I have to check the Hurd code if other object death
notifications are needed).
Reasoning:
* An RPC consists of a send and a reply phase. The only way for a client
to make sure it will reliably receive the reply is to go from the send to
the receive operation atomically _and block_. The server just can
sensibly assume that if the client doesn't care about the reply, it might be
malicious and not sincere.
* Consequence: This allows for a simple way to aviod DoS attacks on
servers, without using redirectors for clients: Every client thread is
only allowed to perform one RPC in any server at the same time. This
means that if a server is processing an RPC by client thread T, then any
further RPC from that thread is rejected until the first one completed.
This makes sure that no more worker threads are created in the server than
there are client threads, and thus provides an easy to enforce upper limit
on the number of required threads. (Note: this is not a strict limit:
Circular calls like Client -> Server S -> Server R -> S -> R -> S ->R...
can increase the number of threads in the servers. But such a setup would
eventually terminate, and doesn't cause real world problems because of trust
restrictions and resource limits).
* Further consequence: Easy RPC interruption! If an RPC in a server is
interrupted by the client (by the signal thread, usually), it can simply
and uniquely be identified by the client's thread ID. No sequence numbers
are needed to distinguish RPCs.
* Good resource tracking: The client pays all costs associated with the RPC.
This is not obvious, so here is an example: an asynchronous msync means
that the client continues to run after the msync() invocation. But that
means that the filesystem would have to pay for a copy of the synced page
until the page is actually written back. This opens a DoS attack. By
requiring the client to provide the page in a container with a synchronous
msync(), the filesystem does not need to pay for a copy and can work on the
client's resources.
I strongly believe in these advantages, so I am going to radically consider
synchronous requirements for the Hurd interfaces. This is not a dogma, but
it will be a strong paradigm. If object death notifications are unnecessary
except for the task server case, we might be able to completely eliminate
the need for notifications entirely (and just have the client poll
blockingly).
This is of course open to discussion. But it solves a lot of otherwise
complicated problems.
Thanks,
Marcus
--
`Rhubarb is no Egyptian god.' GNU http://www.gnu.org address@hidden
Marcus Brinkmann The Hurd http://www.gnu.org/software/hurd/
address@hidden
http://www.marcus-brinkmann.de/