Asynchronous I/O

Asynchronous I/O APIs provide a method for threaded client server models to perform highly concurrent and memory efficient I/O.

In previous threaded client/server models, typically two I/O models have prevailed. The first model dedicated one thread per client connection. The first model consumes too many threads and can incur a substantial sleep and wake up cost. The second model minimizes the number of threads by issuing the select() API on a large set of client connections and delegating a readied client connection or request to a thread. In the second model, you must select or mark on each subsequent select, which can cause a substantial amount of redundant work.

Asynchronous I/O and overlapped I/O resolve both these dilemmas by passing data to and from user buffers after control has been returned to the user application. Asynchronous I/O notifies these worker threads when data is available to be read or when a connection has become ready to transmit data.

Asynchronous I/O advantages

Table 1. Asynchronous I/O APIs
Function Description
gsk_secure_soc_startInit() Starts an asynchronous negotiation of a secure session, using the attributes set for the SSL environment and the secure session.
Note: This API only supports sockets with address family AF_INET or AF_INET6 and type SOCK_STREAM.
gsk_secure_soc_startRecv() Starts an asynchronous receive operation on a secure session.
Note: This API only supports sockets with address family AF_INET or AF_INET6 and type SOCK_STREAM.
gsk_secure_soc_startSend() Starts an asynchronous send operation on a secure session.
Note: This API only supports sockets with address family AF_INET or AF_INET6 and type SOCK_STREAM.
QsoCreateIOCompletionPort() Creates a common wait point for completed asynchronous overlapped I/O operations. The QsoCreateIOCompletionPort() function returns a port handle that represents the wait point. This handle is specified on the QsoStartRecv(), QsoStartSend(), QsoStartAccept(), gsk_secure_soc_startRecv(), or gsk_secure_soc_startSend() functions to initiate asynchronous overlapped I/O operations. Also this handle can be used with QsoPostIOCompletion() to post an event on the associated I/O completion port.
QsoDestroyIOCompletionPort() Destroys an I/O completion port.
QsoWaitForIOCompletionPort() Waits for completed overlapped I/O operation. The I/O completion port represents this wait point.
QsoStartAccept() Starts an asynchronous accept operation.
Note: This API only supports sockets with address family AF_INET or AF_INET6 and type SOCK_STREAM.
QsoStartRecv() Starts an asynchronous receive operation.
Note: This API only supports sockets with address family AF_INET or AF_INET6 and type SOCK_STREAM.
QsoStartSend() Starts an asynchronous send operation.
Note: This API only supports sockets with the AF_INET or AF_INET6 address families with the SOCK_STREAM socket type.
QsoPostIOCompletion() Allows an application to notify a completion port that some function or activity has occurred.

How asynchronous I/O works

An application creates an I/O completion port using the QsoCreateIOCompletionPort() API. This API returns a handle that can be used to schedule and wait for completion of asynchronous I/O requests. The application starts an input or an output function, specifying an I/O completion port handle. When the I/O is completed, status information and an application-defined handle is posted to the specified I/O completion port. The post to the I/O completion port wakes up exactly one of possibly many threads that are waiting. The application receives the following items:

This application handle can be the socket descriptor identifying the client connection, or a pointer to storage that contains extensive information about the state of the client connection. Since the operation was completed and the application handle was passed, the worker thread determines the next step to complete the client connection. Worker threads that process these completed asynchronous operations can handle many different client requests and are not tied to just one. Because copying to and from user buffers occurs asynchronously to the server processes, the wait time for client request diminishes. This can be beneficial on systems where there are multiple processors.

Asynchronous I/O structure

An application that uses asynchronous I/O has the structure demonstrated by the following code fragment.

#include <qsoasync.h>
struct Qso_OverlappedIO_t
{
  Qso_DescriptorHandle_t descriptorHandle;
		void *buffer;
		size_t	 bufferLength;
		int	postFlag : 1;
		int	fillBuffer : 1;
		int	postFlagResult : 1;
		int	reserved1 : 29;
		int	returnValue;
		int	errnoValue;
		int	operationCompleted;
		int	secureDataTransferSize;
		unsigned int	bytesAvailable;
		struct timeval operationWaitTime;
		int	postedDescriptor;
		char reserved2[40];
}
Related reference
Example: Use asynchronous I/O
Socket application design recommendations
Examples: Connection-oriented designs
Example: Use signals with blocking socket APIs
Related information
gsk_secure_soc_startInit()
gsk_secure_soc_startRecv()
gsk_secure_soc_startSend()
QsoCreateIOCompletionPort()
QSoDestroyIOCompletionPort()
QsoWaitForIOCompletionPort()
QsoStartAccept()
QsoStartSend()
QsoStartRecv()
QsoPostIOCompletion()