Asynchronous I/O using standard POSIX calls

*nix systems provide a POSIX standard set of functions for asynchronous I/O.  These functions are:
  • aio_read - Enqueue  a read request.
  • aio_write - Enqueue a write request.
  • aio_fsync - Enqueue a sync request for the I/O operations on a file descriptor.
  • aio_error - Obtain the error status of an enqueued I/O request.
  • aio_return - Obtain the return status of a completed I/O request.
  • aio_suspend - Suspend the caller until one or more of a specified set of I/O requests completes.
  • aio_cancel - Attempt to cancel outstanding I/O requests on a specified file descriptor.
  • lio_listio - Enqueue multiple I/O requests using a single function call.
Some of the names may look familiar because they are designed to provide similar functionality to some of the standard library functions: read, write and fsync.  They can therefore, be used on any file descriptor regardless of whether it represents a file or a socket.  The following code illustrates how to use some of these functions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <aio.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define ITERATIONS 64

int main (void)
{
    const char str[] = "Hello World\n";
    struct aiocb task[ITERATIONS] = {};
    int i;

    const struct aiocb * aiocb_list[ITERATIONS];

    for ( i = 0; i < ITERATIONS; i++ )
    {
       task[i].aio_fildes = STDOUT_FILENO;

       task[i].aio_buf = (void*)str;

       task[i].aio_nbytes = sizeof(str);

       aio_write(&task[i]);

       aiocb_list[i] = &task[i];
    }

    aio_suspend(aiocb_list, ITERATIONS, NULL);

    for ( i = 0; i < ITERATIONS; i++ )
    {
        while( 0 != aio_error(&task[i]) )
            aio_suspend(aiocb_list + i, ITERATIONS - i, NULL);

    }

    return 0;
}

On Linux there is an additional GNU specific function call to fine tune the aio interface:
  • aio_init - Configure aio functionality
This function should be called before using any other aio calls to configure the aio library.  It allows some parameters to be configured including the maximum number of threads used by aio.

These calls can be useful if you just need some basic asynchronous I/O functionality and do not want the overhead of implementing it yourself.  However, the POSIX asynchronous I/O can be viewed as a poor man's implementation.  You could quite easily implement a similar set of functions because the library simply spawns threads and calls the blocking equivalents of the asynchronous I/O functions.  In Linux at least this all takes place exclusively in user space and no kernel support is used.  For this reason in some cases where you only need to utilise a small subset of this functionality you may be better off implementing your own set of function.  However, the library itself has quite a lot of functionality so you may still find it useful.

Linux provides limited kernel support for asynchronous I/O through another set of functions.  I will cover them in another post at a later date.

References:

Comments

Popular Posts