IO can be further extended in a variety of ways. For example, one can release a server process from the duty of supplying each client port with an input buffer capable of holding the largest possible request that can be made by a client. This can be done by allowing the server to specify an ``installments'' option when setting up an input buffer. If client attempts to send a request that is larger than the buffer supplied by a server accepting installments, its request will not fail. Instead, the request will (transparently to the client) be sent over installment by installment, with the server sending a reply to each installment. The details are left to the reader's imagination.
A similar scheme can be devised to allow a server to meet a large client output request, installment by installment - without the client being aware of it.
Put together, these schemes can also be viewed as support for scatter/gather operations - provided that system calls are relatively cheap to make.
It is even possible to extend IO so that it allows ``no-copy'' message transfers between processes with access to shared memory areas. This would be done by providing a sending process with a way to indicate that a buffer is sharable and need not be copied. In addition, a receiver must be able to indicate that it expects a sharable buffer, so that a pointer to the sharable buffer is returned in in-buf.out rather than placing a copy of the message in the buffer pointed to by in-buf.in.
``No-copy'' message transfers can even be made portable to machines without shared memory. Allocating ``sharable'' buffers would simply allocate non-sharable buffers. Sending a ``sharable'' buffer would send a copy and de-allocate the buffer. A ``sharable'' buffer is received by implicitly allocating a receive buffer when the caller specifies that a sharable buffer is expected. This can all be hidden from the programmer by means of suitable subroutine libraries.
Prof Herman Venter