Writing asynchronous I/O models in Linux
It must be noted that asynchronous I/O and multiplexing synchronous I/O (for example, using the select function to select any completed port in the connection pool) are essentially different, both methods can improve efficiency.
The idea of asynchronous I/O is to support asynchronous read/write on a port, and OS support is required for read/write asynchronous system calls. For example, read and write have asynchronous implementation versions, the user calls the asynchronous version of Read and Write. If the port is temporarily unavailable, the user code is immediately returned. You can prepare multiple asynchronous read/write operations for the same port to make full use of port resources and reduce the time that the user is suspended while waiting for the port to be available.
I. asynchronous I/O model in Windows
It is implemented through overlapped structure and waitformultipleobjects/waitformultipleevents.
The sample code is as follows:
Handle hfile = createfile (..., file_flag_overlapped ,...);
Byte bbuffer [10];
Overlapped oread = {0 };
Oread. offset = 0;
Oread. hevent = createevent (...);
Readfile (hfile, bbuffer, 10, null, & oread );
Overlapped owrite = {0 };
Owrite. offset = 10;
Owrite. hevent = createevent (...);
Writefile (hfile, "Jeff", 5, null, & owrite );
Handle H [2];
H [0] = oread. hevent;
H [1] = owrite. hevent;
Dword dw = waitformultipleobjects (2, H, false, infinite );
Switch (DW _ wait_object_0 ){
Case 0: // read completed
Break;
Case 1: // write completed
Break;
}
Ii. asynchronous I/O model in Linux
In Linux, system calls such as overlapped structure and waitformultipleobjects/waitformultipleevents do not exist. Therefore, you need to encapsulate some functions to facilitate asynchronous operations.
This topic implements asynchronous I/O functions defined in posix1003.1b Based on Linux kernel. The basic idea is that when a process has an asynchronous I/O request, it creates a queue for the process to queue all its asynchronous requests, create a kernel thread for the queue to complete the actual I/O operations in the queue. Asynchronous I/O system calls only add I/O requests to the queue of calling processes. If the process that calls this function is the first time to send an asynchronous I/O request, first, you need to create a queue of asynchronous I/O requests and corresponding kernel threads for the process, and then the process returns directly without waiting for I/O to complete. When the actual I/O operation is complete, the kernel sends a signal to notify the process of I/O completion.
2.1 asynchronous request control block aiocb
This structure is the main parameter for asynchronous I/O system calls. It contains all the information required for asynchronous operations and is the most basic and important data structure, including the operation (read or write) to be performed and its priority, requested file descriptor, offset, number of bytes, and buffer address.
Struct aiocb
{
/* The values of the following seven members are provided by the user to determine the parameters of asynchronous I/O Requests */
Intaiofildes;/* file descriptor *
/Intaiolioopcode;/* I/O operation type */
Intaioreqprio;/* priority */
Void * aiobuf;/* buffer */
Size_t aionbytes;/* number of bytes */
Struct sigevent aiosigevent;/* semaphore */
Loff_t aiooffset;/* file offset */
/* The following are internal members, and users do not need to provide */
Kaio_key_t aiokey;
Unsigned long aiotimes;/* Actual I/O completion time */
Int aioerror;/* returned value of aioerror */
Ssize_t aioreturn;/* returned value of aioreturn */
}
2.2 kernel asynchronous request control block kaiocb
This structure is the asynchronous I/O information provided to the kernel, including all information in the structure aiocb and other related data structures.
Structkaiocb
{
Struct aiocb * kaiouaiocb;/* User-provided aiocb */
Struct file * kaiofilp;
Void * kaiobuf;
Size_t kaionbytes;
Loff_t kaiooffset;
Int kaiocmd;/* I/O operation: Read | write | fsync */
Int kaioerror;
Int kaioid;/* kaiocb descriptor */
Struct kaiocb * kaiohnext;/* pointer after hash table */
Struct kaiocb ** kaiohpprev;/* pre-Hash Table pointer */
Struct liocb * kaioliocb;/* listi/o control block pointer */
Struct waitqueue ** kaiosuspendwait;
Struct taskstruct * kaiotask;/* request process */
Struct kaio_list_head_kaio_ioq;/* asynchronous request queue header pointer */
Void * kaiokq;/* asynchronous request queue */
Struct sigevent kaiosigevent;/* notification semaphore */
Unsigned long kaiotimes [aiotimes];
# Definek aiosettime (K, x) (k)-> kaiotimes [(x)] = kaiotime ()
}
2.3 asynchronous request queue
This queue is a two-way circular linked list. Each process with an asynchronous request creates an asynchronous request queue. All asynchronous requests of the process are queued in the queue.
Struct kaio_queue
{
Spinlock_t kaioq_lock;
Structkaiolisthead kaioq;
Int kaioqref;
Int threads;
}
2.4 Algorithm
Taking asynchronous read aioread as an example, this function is used to copy the specified file content to the specified buffer based on the information provided by the asynchronous I/O control block aiocb.
Algorithm aioread
Input: asynchronous I/O, control block aiocb
Output: 0 is returned for success, and-1 is returned for failure.
{
If (the process sends an asynchronous request for the first time, and there is no asynchronous request queue)
Create an asynchronous request queue KQ for it;
If (the current number of asynchronous requests is greater than the maximum value specified by the System)
Error returned;
If (the file specified by aiocb is invalid)
Error returned;
Set the values of each domain of the kernel asynchronous I/O control block kiocb according to aiocb;
Call kaiocbenqueue to send a request to the queue;
If (returns if the team fails to join)
Error returned;
Function return;
}
Algorithm kaiocbenqueue
Input: asynchronous request queue KQ, Kernel Asynchronous I/O control block kaiocb
Output: 0 is returned for success, and an error code is returned for failure.
{
Insert kaiocb into the corresponding location of the asynchronous request queue KQ;
If (KQ does not have a kernel service thread for specific I/O operations)
Call kernelthread (handleio, kaiocb, 0) to create a kernel thread. (handleio is the execution function of the thread );
Function return;
}
Handleio Algorithm
Input: Kernel Asynchronous I/O control block kaiocb
Output: 0 is returned for success, and an error code is returned for failure.
{
While (the queue is not empty)
{
Execute fop-> read for the underlying I/O operations of the file;
After the operation, delete the request from the queue;
}
Send a signal to the process kaiocb-> kaiotask-> kaiosigevent to notify the process that I/O operations are completed;
Function return;
}