NAME
aio —
asynchronous I/O
(REALTIME)
LIBRARY
POSIX Real-time Library (librt, -lrt)
SYNOPSIS
#include <aio.h>
DESCRIPTION
The
IEEE Std 1003.1-2001 (“POSIX.1”)
standard defines an interface for asynchronous input and output. Although in
NetBSD this is provided as part of the
POSIX Real-time Library (librt, -lrt), the
implementation largely resides in the kernel.
Rationale
The rationale can be roughly summarized with the following points.
- To increase performance by providing a mechanism to carry
out I/O without blocking. Theoretically, if I/O would never block, neither
at the software nor at the hardware level, the overhead of I/O would
become zero, and processes would no longer be I/O bound.
- To segregate the different I/O operations into logically
distinctive procedures. Unlike with the standard
stdio(3), the
aio interface separates queuing and submitting I/O
operations to the kernel, and receiving notifications of operation
completion from the kernel.
- To provide an uniform and standardized framework for
asynchronous I/O. For instance, aio avoids the need for
(and the overhead of) extra worker threads sometimes used to perform
asynchronous I/O.
Asynchronous I/O Control
Block
The Asynchronous I/O Control Block is the basic operational unit behind
aio. This is required since an arbitrary number of
operations can be started at once, and because each operation can be either
input or output. This block is represented by the
aiocb
structure, which is defined in the
<aio.h> header. The following fields
are available for user applications:
off_t aio_offset;
void *aio_buf;
size_t aio_nbytes;
int aio_fildes;
int aio_lio_opcode;
int aio_reqprio;
struct sigevent aio_sigevent;
The fields are:
- The aio_offset specifies the
implicit file offset at which the I/O operations are performed. This
cannot be expected to be the actual read/write offset of the file
descriptor.
- The aio_buf member is a pointer to
the buffer to which data is going to be written or to which the read
operation stores data.
- The aio_nbytes specifies the length
of aio_buf.
- The aio_fildes specifies the used
file descriptor.
- The aio_lio_opcode is used by the
lio_listio() function to initialize a list of I/O
requests with a single call.
- The aio_reqprio member can be used
to lower the scheduling priority of an aio operation.
This is only available if
_POSIX_PRIORITIZED_IO
and _POSIX_PRIORITY_SCHEDULING
are defined, and
the associated file descriptor supports it.
- The aio_sigevent member is used to
specify how the calling process is notified once an aio
operation completes.
The members
aio_buf,
aio_fildes, and
aio_nbytes are conceptually similar to the parameters
‘buf’, ‘fildes’, and ‘nbytes’ used in the
standard
read(2) and
write(2) functions. For example,
the caller can read
aio_nbytes from a file associated
with the file descriptor
aio_fildes into the buffer
aio_buf. All appropriate fields should be initialized by
the caller before
aio_read() or
aio_write() is called.
File Offsets
Asynchronous I/O operations are not strictly sequential; operations are carried
out in arbitrary order and more than one operation for one file descriptor can
be started. The requested read or write operation starts from the absolute
position specified by
aio_offset, as if
lseek(2) would have been called
with
SEEK_SET
immediately prior to the operation. The
POSIX standard does not specify what happens after an
aio
operation has been successfully completed. Depending on the implementation,
the actual file offset may or may not be updated.
Errors and Completion
Asynchronous I/O operations are said to be complete when:
- An error is detected.
- The I/O transfer is performed successfully.
- The operation is canceled.
If an error condition is detected that prevents an operation from being started,
the request is not enqueued. In this case the read and write functions,
aio_read() and
aio_write(), return
immediately, setting the global
errno to indicate the
cause of the error.
After an operation has been successfully enqueued,
aio_error()
and
aio_return() must be used to determine the status of the
operation and to determine any error conditions. This includes the conditions
reported by the standard
read(2),
write(2), and
fsync(2). The request remains
enqueued and consumes process and system resources until
aio_return() is called.
Waiting for Completion
The
aio interface supports both polling and notification
models. The first can be implemented by simply repeatedly calling the
aio_error() function to test the status of an operation.
Once the operation has completed,
aio_return() is used to
free the
aiocb structure for re-use.
The notification model is implemented by using the
aio_sigevent member of the Asynchronous I/O Control
Block. The operational model and the used structure are described in
sigevent(3).
The
aio_suspend() function can be used to wait for the
completion of one or more operations. It is possible to set a timeout so that
the process can continue the execution and take recovery actions if the
aio operations do not complete as expected.
Cancellation and
Synchronization
The
aio_cancel() function can be used to request cancellation
of an asynchronous I/O operation. Note however that not all of them can be
canceled. The same
aiocb used to start the operation may
be used as a handle for identification. It is also possible to request
cancellation of all operations pending for a file.
Comparable to
fsync(2), the
aio_fsync() function can be used to synchronize the contents
of permanent storage when multiple asynchronous I/O operations are outstanding
for the file or device. The synchronization operation includes only those
requests that have already been successfully enqueued.
FUNCTIONS
The following functions comprise the API of the
aio interface:
COMPATIBILITY
Unfortunately, the POSIX asynchronous I/O implementations vary slightly. Some
implementations provide a slightly different API with possible extensions. For
instance, the
FreeBSD implementation uses a function
‘
aio_waitcomplete()’ to wait for the next
completion of an
aio request.
STANDARDS
The
aio interface is expected to conform to the
IEEE Std 1003.1-2001 (“POSIX.1”) standard.
HISTORY
The
aio interface first appeared in
NetBSD
5.0.
CAVEATS
Few limitations can be mentioned:
- Undefined behavior results if simultaneous asynchronous
operations use the same Asynchronous I/O Control Block.
- When an asynchronous read operation is outstanding,
undefined behavior may follow if the contents of
aiocb are altered, or if memory associated with the
structure, or the aio_buf buffer, is
deallocated.