#### 13.10.1 Asynchronous Read and Write Operations

— Function: int aio_read (struct aiocb *aiocbp)

> This function initiates an asynchronous read operation. It immediately returns after the operation was enqueued or when an error was encountered.

> The first `aiocbp->aio_nbytes` bytes of the file for which `aiocbp->aio_fildes` is a descriptor are written to the buffer starting at `aiocbp->aio_buf`. Reading starts at the absolute position `aiocbp->aio_offset` in the file.

> If prioritized I/O is supported by the platform the `aiocbp->aio_reqprio` value is used to adjust the priority before the request is actually enqueued.

> The calling process is notified about the termination of the read request according to the `aiocbp->aio_sigevent` value.

> When `aio_read` returns, the return value is zero if no error occurred that can be found before the process is enqueued. If such an early error is found, the function returns -1 and sets `errno` to one of the following values:

> `EAGAIN`
>   The request was not enqueued due to (temporarily) exceeded resource limitations.
> `ENOSYS`
>   The `aio_read` function is not implemented.
> `EBADF`
>   The `aiocbp->aio_fildes` descriptor is not valid. This condition need not be recognized before enqueueing the request and so this error might also be signaled asynchronously.
> `EINVAL`
>   The `aiocbp->aio_offset` or `aiocbp->aio_reqpiro` value is invalid. This condition need not be recognized before enqueueing the request and so this error might also be signaled asynchronously.

> If `aio_read` returns zero, the current status of the request can be queried using `aio_error` and `aio_return` functions. As long as the value returned by `aio_error` is `EINPROGRESS` the operation has not yet completed. If `aio_error` returns zero, the operation successfully terminated, otherwise the value is to be interpreted as an error code. If the function terminated, the result of the operation can be obtained using a call to `aio_return`. The returned value is the same as an equivalent call to `read` would have returned. Possible error codes returned by `aio_error` are:

> `EBADF`
>   The `aiocbp->aio_fildes` descriptor is not valid.
> `ECANCELED`
>   The operation was canceled before the operation was finished (see Cancel AIO Operations)
> `EINVAL`
>   The `aiocbp->aio_offset` value is invalid.

> When the sources are compiled with `_FILE_OFFSET_BITS == 64` this function is in fact `aio_read64` since the LFS interface transparently replaces the normal implementation.

— Function: int aio_read64 (struct aiocb64 *aiocbp)

> This function is similar to the `aio_read` function. The only difference is that on 32 bit machines, the file descriptor should be opened in the large file mode. Internally, `aio_read64` uses functionality equivalent to `lseek64` (see File Position Primitive) to position the file descriptor correctly for the reading, as opposed to `lseek` functionality used in `aio_read`.

> When the sources are compiled with `_FILE_OFFSET_BITS == 64`, this function is available under the name `aio_read` and so transparently replaces the interface for small files on 32 bit machines.

To write data asynchronously to a file, there exists an equivalent pair of functions with a very similar interface.

— Function: int aio_write (struct aiocb *aiocbp)

> This function initiates an asynchronous write operation. The function call immediately returns after the operation was enqueued or if before this happens an error was encountered.

> The first `aiocbp->aio_nbytes` bytes from the buffer starting at `aiocbp->aio_buf` are written to the file for which `aiocbp->aio_fildes` is an descriptor, starting at the absolute position `aiocbp->aio_offset` in the file.

> If prioritized I/O is supported by the platform, the `aiocbp->aio_reqprio` value is used to adjust the priority before the request is actually enqueued.

> The calling process is notified about the termination of the read request according to the `aiocbp->aio_sigevent` value.

> When `aio_write` returns, the return value is zero if no error occurred that can be found before the process is enqueued. If such an early error is found the function returns -1 and sets `errno` to one of the following values.

> `EAGAIN`
>   The request was not enqueued due to (temporarily) exceeded resource limitations.
> `ENOSYS`
>   The `aio_write` function is not implemented.
> `EBADF`
>   The `aiocbp->aio_fildes` descriptor is not valid. This condition may not be recognized before enqueueing the request, and so this error might also be signaled asynchronously.
> `EINVAL`
>   The `aiocbp->aio_offset` or `aiocbp->aio_reqprio` value is invalid. This condition may not be recognized before enqueueing the request and so this error might also be signaled asynchronously.

> In the case `aio_write` returns zero, the current status of the request can be queried using `aio_error` and `aio_return` functions. As long as the value returned by `aio_error` is `EINPROGRESS` the operation has not yet completed. If `aio_error` returns zero, the operation successfully terminated, otherwise the value is to be interpreted as an error code. If the function terminated, the result of the operation can be get using a call to `aio_return`. The returned value is the same as an equivalent call to `read` would have returned. Possible error codes returned by `aio_error` are:

> `EBADF`
>   The `aiocbp->aio_fildes` descriptor is not valid.
> `ECANCELED`
>   The operation was canceled before the operation was finished. (see Cancel AIO Operations)
> `EINVAL`
>   The `aiocbp->aio_offset` value is invalid.

> When the sources are compiled with `_FILE_OFFSET_BITS == 64`, this function is in fact `aio_write64` since the LFS interface transparently replaces the normal implementation.

— Function: int aio_write64 (struct aiocb64 *aiocbp)

> This function is similar to the `aio_write` function. The only difference is that on 32 bit machines the file descriptor should be opened in the large file mode. Internally `aio_write64` uses functionality equivalent to `lseek64` (see File Position Primitive) to position the file descriptor correctly for the writing, as opposed to `lseek` functionality used in `aio_write`.

> When the sources are compiled with `_FILE_OFFSET_BITS == 64`, this function is available under the name `aio_write` and so transparently replaces the interface for small files on 32 bit machines.

Besides these functions with the more or less traditional interface, POSIX.1b also defines a function which can initiate more than one operation at a time, and which can handle freely mixed read and write operations. It is therefore similar to a combination of `readv` and `writev`.

— Function: int lio_listio (int mode, struct aiocb *const list[], int nent, struct sigevent *sig)

> The `lio_listio` function can be used to enqueue an arbitrary number of read and write requests at one time. The requests can all be meant for the same file, all for different files or every solution in between.

> `lio_listio` gets the nent requests from the array pointed to by list. The operation to be performed is determined by the `aio_lio_opcode` member in each element of list. If this field is `LIO_READ` a read operation is enqueued, similar to a call of `aio_read` for this element of the array (except that the way the termination is signalled is different, as we will see below). If the `aio_lio_opcode` member is `LIO_WRITE` a write operation is enqueued. Otherwise the `aio_lio_opcode` must be `LIO_NOP` in which case this element of list is simply ignored. This “operation” is useful in situations where one has a fixed array of `struct aiocb` elements from which only a few need to be handled at a time. Another situation is where the `lio_listio` call was canceled before all requests are processed (see Cancel AIO Operations) and the remaining requests have to be reissued.

> The other members of each element of the array pointed to by `list` must have values suitable for the operation as described in the documentation for `aio_read` and `aio_write` above.

> The mode argument determines how `lio_listio` behaves after having enqueued all the requests. If mode is `LIO_WAIT` it waits until all requests terminated. Otherwise mode must be `LIO_NOWAIT` and in this case the function returns immediately after having enqueued all the requests. In this case the caller gets a notification of the termination of all requests according to the sig parameter. If sig is `NULL` no notification is send. Otherwise a signal is sent or a thread is started, just as described in the description for `aio_read` or `aio_write`.

> If mode is `LIO_WAIT`, the return value of `lio_listio` is 0 when all requests completed successfully. Otherwise the function return -1 and `errno` is set accordingly. To find out which request or requests failed one has to use the `aio_error` function on all the elements of the array list.

> In case mode is `LIO_NOWAIT`, the function returns 0 if all requests were enqueued correctly. The current state of the requests can be found using `aio_error` and `aio_return` as described above. If `lio_listio` returns -1 in this mode, the global variable `errno` is set accordingly. If a request did not yet terminate, a call to `aio_error` returns `EINPROGRESS`. If the value is different, the request is finished and the error value (or 0) is returned and the result of the operation can be retrieved using `aio_return`.

> Possible values for `errno` are:

> `EAGAIN`
>   The resources necessary to queue all the requests are not available at the moment. The error status for each element of list must be checked to determine which request failed.

>   Another reason could be that the system wide limit of AIO requests is exceeded. This cannot be the case for the implementation on GNU systems since no arbitrary limits exist.

> `EINVAL`
>   The mode parameter is invalid or nent is larger than `AIO_LISTIO_MAX`.
> `EIO`
>   One or more of the request's I/O operations failed. The error status of each request should be checked to determine which one failed.
> `ENOSYS`
>   The `lio_listio` function is not supported.

> If the mode parameter is `LIO_NOWAIT` and the caller cancels a request, the error status for this request returned by `aio_error` is `ECANCELED`.

> When the sources are compiled with `_FILE_OFFSET_BITS == 64`, this function is in fact `lio_listio64` since the LFS interface transparently replaces the normal implementation.

— Function: int lio_listio64 (int mode, struct aiocb64 *const list[], int nent, struct sigevent *sig)

> This function is similar to the `lio_listio` function. The only difference is that on 32 bit machines, the file descriptor should be opened in the large file mode. Internally, `lio_listio64` uses functionality equivalent to `lseek64` (see File Position Primitive) to position the file descriptor correctly for the reading or writing, as opposed to `lseek` functionality used in `lio_listio`.

> When the sources are compiled with `_FILE_OFFSET_BITS == 64`, this function is available under the name `lio_listio` and so transparently replaces the interface for small files on 32 bit machines.