No realistic operating system can afford to omit provision for non-blocking forms of I/O. Consequently there is the need to provide three variant forms of IO, namely Initiate-IO, Complete-IO and Try-to-complete-IO.
Initiate-IO takes the I/O operation up to the point where the parameters and output have been sent off to the other process (or device driver or file system), but does not wait for a reply. Complete-IO goes on where Initiate-IO left off. If no reply has been received in the mean time, Complete-IO waits for one to arrive. Try-to-complete-IO is a version of Complete-IO that will return (setting a status code) rather than wait for a reply.
When used for IPC, asynchronous I/O makes it possible to write server processes that serve several client processes, since it allows a server to have several incomplete I/O operations. Of course, the server will have to use a different I/O port for each client. And, since an I/O operation will complete on a particular port only if the corresponding client makes a request, a server waiting to serve the next request from any client should never wait on a particular client port. Nor is it acceptable for the server to sit in a busy loop, polling its I/O ports with Try-to-complete-IO.
The solution is to introduce an ``any port'' value that can be supplied as io-port.in to Complete-IO and Try-to-complete-IO. In such cases the caller is suspended until an I/O operation completes on any of its ports. The I/O port selected is returned as io-port.out. The value of in-buf.out is taken from the value of in-buf.in supplied to the call to Initiate-IO that started the I/O operation on the port concerned.
Prof Herman Venter