Search code examples
clinuxaio

Errors of aio_write


I'm rewriting a write to aio_write so I can deal with timeouts (and I don't want to bother with select). One thing that I don't understand from the man pages is how can the aio_write fail.

For write I'm mostly interested in partial writes and EINTR. Can aio_write (aio_error to be precise) return EINTR or do partial write?


Solution

  • One thing that I don't understand from the man pages is how can the aio_write fail.

    aio_write(3) per se rarely fails, only if you give it bad data or the system is out of resources.

    aio_error(3), on the other hand, is what you use to check the status of queued (or perhaps already completed) operations.

    So, yes, aio_error(3) can return EINTR under the same conditions that write(2) would return it: if a signal was caught before writing has started, and the signal handler returned (and the signal handler was not set up with the SA_RESTART flag in the sa_flags field of struct sigaction, otherwise the syscall would be automatically restarted and you wouldn't see EINTR).

    As for partial writes, it can also happen - again, under the same conditions as it would for write(2) - but you can't check this from the return value of aio_error(3). The usual flow is as follows:

    • You call aio_error(3) to see if the operation is in progress or is completed (or was canceled). If it returns anything other than 0, then either there was an error, it's in progress, or it was canceled. So, no writes actually happened and you cannot call aio_return(3). If it's in progress, either do something else and try again later, or use aio_suspend(3) to wait for it to complete.
    • If aio_error(3) returns 0, then it means that the request completed successfully. Partial writes are interpreted as success. So then you call aio_return(3) to get the actual return value from the underlying write(2) that took place: this is when you can check for partial writes.

    Note that partial writes are not necessarily an error; that's why aio_error(3) doesn't treat them like so. For example, a pipe write channel with O_NONBLOCK enabled may write less bytes than requested if there isn't enough capacity to write all of them.