- Operating System Support
- The Basic API
- The AIO Control Block
- Asynchronous Completion
- List I/O
- Limitations of AIO
The AIO Control Block
The basic data structure used by all AIO operations is the aiocb structure, which contains the metadata about the operation. The fields in the following table are the most important.
Field |
Contents |
aio_nbytes |
The number of bytes to be read or written by this operation. |
aio_filedes |
The file descriptor of the file to access. |
aio_buf |
A pointer to the data to be written, or the location to store data to be read. |
aio_offset |
The offset from the start of the file. |
A few other attributes (some of which will be discussed later) are used occasionally, but these four are the most important. Using these fields, we can write a simple program, aio1.c, to read data from a file:
#include <aio.h> #include <stdio.h> int main(int argc, char * argv[]) { if(argc != 2) { printf("Usage: %s {filename}\n", argv[0]); return -1; } struct aiocb cb; struct aiocb * cbs[1]; //Open the file specified on the command line FILE * file = fopen(argv[1], "r+"); //Set up the control block cb.aio_buf = malloc(11); cb.aio_fildes = fileno(file); cb.aio_nbytes = 10; cb.aio_offset = 0; //Perform the read aio_read(&cb); //Wait for it to complete cbs[0] = &cb; aio_suspend(cbs, 1, NULL); printf("AIO operation returned %d\n", aio_return(&cb)); return 0; }
This example isn’t particularly useful; it does nothing that couldn’t be done with a synchronous read. It does, however, illustrate the principle. We can compile and run the program as follows (don’t forget to add -lrt to the gcc command line if you’re on Linux):
$ gcc aio1.c $ echo 12345678901234567890 > bar $ ./a.out bar 10
The three AIO calls used here dispatch the request, wait for it to complete, and then find its return value. The aio_return(2) function will return exactly the same value that read(2) would have done if you had performed a synchronous read—that is, the number of bytes read, or -1, indicating an error. Note that aio_suspend(2) takes an array of aiocbs, and will return when any of them has completed or when a signal has been received. If you want to check whether an AIO operation has really completed, you can use aio_error(2), which returns EINPROGRESS if the operation hasn’t yet finished.
FreeBSD offers an alternate method of waiting for an AIO operation to complete: aio_waitcomplete(2) combines the functionality of aio_suspend(2) and aio_return(2). It returns both the aiocb corresponding to the operation to complete and the return value. While this is often a nice feature, its use is discouraged because it results in non-portable code.