| '\" t |
| .\" Copyright (c) 2010 by Michael Kerrisk <mtk.manpages@gmail.com> |
| .\" |
| .\" %%%LICENSE_START(VERBATIM) |
| .\" Permission is granted to make and distribute verbatim copies of this |
| .\" manual provided the copyright notice and this permission notice are |
| .\" preserved on all copies. |
| .\" |
| .\" Permission is granted to copy and distribute modified versions of this |
| .\" manual under the conditions for verbatim copying, provided that the |
| .\" entire resulting derived work is distributed under the terms of a |
| .\" permission notice identical to this one. |
| .\" |
| .\" Since the Linux kernel and libraries are constantly changing, this |
| .\" manual page may be incorrect or out-of-date. The author(s) assume no |
| .\" responsibility for errors or omissions, or for damages resulting from |
| .\" the use of the information contained herein. The author(s) may not |
| .\" have taken the same level of care in the production of this manual, |
| .\" which is licensed free of charge, as they might when working |
| .\" professionally. |
| .\" |
| .\" Formatted or processed versions of this manual, if unaccompanied by |
| .\" the source, must acknowledge the copyright and authors of this work. |
| .\" %%%LICENSE_END |
| .\" |
| .TH AIO 7 2016-03-15 "Linux" "Linux Programmer's Manual" |
| .SH NAME |
| aio \- POSIX asynchronous I/O overview |
| .SH DESCRIPTION |
| The POSIX asynchronous I/O (AIO) interface allows applications |
| to initiate one or more I/O operations that are performed |
| asynchronously (i.e., in the background). |
| The application can elect to be notified of completion of |
| the I/O operation in a variety of ways: |
| by delivery of a signal, by instantiation of a thread, |
| or no notification at all. |
| |
| The POSIX AIO interface consists of the following functions: |
| .TP 16 |
| .BR aio_read (3) |
| Enqueue a read request. |
| This is the asynchronous analog of |
| .BR read (2). |
| .TP |
| .BR aio_write (3) |
| Enqueue a write request. |
| This is the asynchronous analog of |
| .BR write (2). |
| .TP |
| .BR aio_fsync (3) |
| Enqueue a sync request for the I/O operations on a file descriptor. |
| This is the asynchronous analog of |
| .BR fsync (2) |
| and |
| .BR fdatasync (2). |
| .TP |
| .BR aio_error (3) |
| Obtain the error status of an enqueued I/O request. |
| .TP |
| .BR aio_return (3) |
| Obtain the return status of a completed I/O request. |
| .TP |
| .BR aio_suspend (3) |
| Suspend the caller until one or more of a specified set of |
| I/O requests completes. |
| .TP |
| .BR aio_cancel (3) |
| Attempt to cancel outstanding I/O requests on a specified |
| file descriptor. |
| .TP |
| .BR lio_listio (3) |
| Enqueue multiple I/O requests using a single function call. |
| .PP |
| The |
| .I aiocb |
| ("asynchronous I/O control block") structure defines |
| parameters that control an I/O operation. |
| An argument of this type is employed with all of the functions listed above. |
| This structure has the following form: |
| .PP |
| .in +4n |
| .nf |
| #include <aiocb.h> |
| |
| struct aiocb { |
| /* The order of these fields is implementation-dependent */ |
| |
| int aio_fildes; /* File descriptor */ |
| off_t aio_offset; /* File offset */ |
| volatile void *aio_buf; /* Location of buffer */ |
| size_t aio_nbytes; /* Length of transfer */ |
| int aio_reqprio; /* Request priority */ |
| struct sigevent aio_sigevent; /* Notification method */ |
| int aio_lio_opcode; /* Operation to be performed; |
| lio_listio() only */ |
| |
| /* Various implementation-internal fields not shown */ |
| }; |
| |
| /* Operation codes for \(aqaio_lio_opcode\(aq: */ |
| |
| enum { LIO_READ, LIO_WRITE, LIO_NOP }; |
| |
| .fi |
| .in |
| The fields of this structure are as follows: |
| .TP 16 |
| .I aio_filedes |
| The file descriptor on which the I/O operation is to be performed. |
| .TP |
| .I aio_offset |
| This is the file offset at which the I/O operation is to be performed. |
| .TP |
| .I aio_buf |
| This is the buffer used to transfer data for a read or write operation. |
| .TP |
| .I aio_nbytes |
| This is the size of the buffer pointed to by |
| .IR aio_buf . |
| .TP |
| .I aio_reqprio |
| This field specifies a value that is subtracted |
| from the calling thread's real-time priority in order to |
| determine the priority for execution of this I/O request (see |
| .BR pthread_setschedparam (3)). |
| The specified value must be between 0 and the value returned by |
| .IR sysconf(_SC_AIO_PRIO_DELTA_MAX) . |
| This field is ignored for file synchronization operations. |
| .TP |
| .I aio_sigevent |
| This field is a structure that specifies how the caller is |
| to be notified when the asynchronous I/O operation completes. |
| Possible values for |
| .IR aio_sigevent.sigev_notify |
| are |
| .BR SIGEV_NONE , |
| .BR SIGEV_SIGNAL , |
| and |
| .BR SIGEV_THREAD . |
| See |
| .BR sigevent (7) |
| for further details. |
| .TP |
| .I aio_lio_opcode |
| The type of operation to be performed; used only for |
| .BR lio_listio (3). |
| .PP |
| In addition to the standard functions listed above, |
| the GNU C library provides the following extension to the POSIX AIO API: |
| .TP 16 |
| .BR aio_init (3) |
| Set parameters for tuning the behavior of the glibc POSIX AIO implementation. |
| .SH ERRORS |
| .TP |
| .B EINVAL |
| The |
| .I aio_reqprio |
| field of the |
| .I aiocb |
| structure was less than 0, |
| or was greater than the limit returned by the call |
| .IR sysconf(_SC_AIO_PRIO_DELTA_MAX) . |
| .SH VERSIONS |
| The POSIX AIO interfaces are provided by glibc since version 2.1. |
| .SH CONFORMING TO |
| POSIX.1-2001, POSIX.1-2008. |
| .SH NOTES |
| It is a good idea to zero out the control block buffer before use (see |
| .BR memset (3)). |
| The control block buffer and the buffer pointed to by |
| .I aio_buf |
| must not be changed while the I/O operation is in progress. |
| These buffers must remain valid until the I/O operation completes. |
| |
| Simultaneous asynchronous read or write operations using the same |
| .I aiocb |
| structure yield undefined results. |
| |
| The current Linux POSIX AIO implementation is provided in user space by glibc. |
| This has a number of limitations, most notably that maintaining multiple |
| threads to perform I/O operations is expensive and scales poorly. |
| Work has been in progress for some time on a kernel |
| state-machine-based implementation of asynchronous I/O |
| (see |
| .BR io_submit (2), |
| .BR io_setup (2), |
| .BR io_cancel (2), |
| .BR io_destroy (2), |
| .BR io_getevents (2)), |
| but this implementation hasn't yet matured to the point where |
| the POSIX AIO implementation can be completely |
| reimplemented using the kernel system calls. |
| .\" http://lse.sourceforge.net/io/aio.html |
| .\" http://lse.sourceforge.net/io/aionotes.txt |
| .\" http://lwn.net/Articles/148755/ |
| .SH EXAMPLE |
| The program below opens each of the files named in its command-line |
| arguments and queues a request on the resulting file descriptor using |
| .BR aio_read (3). |
| The program then loops, |
| periodically monitoring each of the I/O operations |
| that is still in progress using |
| .BR aio_error (3). |
| Each of the I/O requests is set up to provide notification by delivery |
| of a signal. |
| After all I/O requests have completed, |
| the program retrieves their status using |
| .BR aio_return (3). |
| |
| The |
| .B SIGQUIT |
| signal (generated by typing control-\\) causes the program to request |
| cancellation of each of the outstanding requests using |
| .BR aio_cancel (3). |
| |
| Here is an example of what we might see when running this program. |
| In this example, the program queues two requests to standard input, |
| and these are satisfied by two lines of input containing |
| "abc" and "x". |
| |
| .in +4n |
| .nf |
| $ \fB./a.out /dev/stdin /dev/stdin\fP |
| opened /dev/stdin on descriptor 3 |
| opened /dev/stdin on descriptor 4 |
| aio_error(): |
| for request 0 (descriptor 3): In progress |
| for request 1 (descriptor 4): In progress |
| \fBabc\fP |
| I/O completion signal received |
| aio_error(): |
| for request 0 (descriptor 3): I/O succeeded |
| for request 1 (descriptor 4): In progress |
| aio_error(): |
| for request 1 (descriptor 4): In progress |
| \fBx\fP |
| I/O completion signal received |
| aio_error(): |
| for request 1 (descriptor 4): I/O succeeded |
| All I/O requests completed |
| aio_return(): |
| for request 0 (descriptor 3): 4 |
| for request 1 (descriptor 4): 2 |
| .fi |
| .in |
| .SS Program source |
| \& |
| .nf |
| #include <fcntl.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <aio.h> |
| #include <signal.h> |
| |
| #define BUF_SIZE 20 /* Size of buffers for read operations */ |
| |
| #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) |
| |
| #define errMsg(msg) do { perror(msg); } while (0) |
| |
| struct ioRequest { /* Application\-defined structure for tracking |
| I/O requests */ |
| int reqNum; |
| int status; |
| struct aiocb *aiocbp; |
| }; |
| |
| static volatile sig_atomic_t gotSIGQUIT = 0; |
| /* On delivery of SIGQUIT, we attempt to |
| cancel all outstanding I/O requests */ |
| |
| static void /* Handler for SIGQUIT */ |
| quitHandler(int sig) |
| { |
| gotSIGQUIT = 1; |
| } |
| |
| #define IO_SIGNAL SIGUSR1 /* Signal used to notify I/O completion */ |
| |
| static void /* Handler for I/O completion signal */ |
| aioSigHandler(int sig, siginfo_t *si, void *ucontext) |
| { |
| if (si->si_code == SI_ASYNCIO) { |
| write(STDOUT_FILENO, "I/O completion signal received\\n", 31); |
| |
| /* The corresponding ioRequest structure would be available as |
| struct ioRequest *ioReq = si\->si_value.sival_ptr; |
| and the file descriptor would then be available via |
| ioReq\->aiocbp\->aio_fildes */ |
| } |
| } |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| struct ioRequest *ioList; |
| struct aiocb *aiocbList; |
| struct sigaction sa; |
| int s, j; |
| int numReqs; /* Total number of queued I/O requests */ |
| int openReqs; /* Number of I/O requests still in progress */ |
| |
| if (argc < 2) { |
| fprintf(stderr, "Usage: %s <pathname> <pathname>...\\n", |
| argv[0]); |
| exit(EXIT_FAILURE); |
| } |
| |
| numReqs = argc \- 1; |
| |
| /* Allocate our arrays */ |
| |
| ioList = calloc(numReqs, sizeof(struct ioRequest)); |
| if (ioList == NULL) |
| errExit("calloc"); |
| |
| aiocbList = calloc(numReqs, sizeof(struct aiocb)); |
| if (aiocbList == NULL) |
| errExit("calloc"); |
| |
| /* Establish handlers for SIGQUIT and the I/O completion signal */ |
| |
| sa.sa_flags = SA_RESTART; |
| sigemptyset(&sa.sa_mask); |
| |
| sa.sa_handler = quitHandler; |
| if (sigaction(SIGQUIT, &sa, NULL) == \-1) |
| errExit("sigaction"); |
| |
| sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| sa.sa_sigaction = aioSigHandler; |
| if (sigaction(IO_SIGNAL, &sa, NULL) == \-1) |
| errExit("sigaction"); |
| |
| /* Open each file specified on the command line, and queue |
| a read request on the resulting file descriptor */ |
| |
| for (j = 0; j < numReqs; j++) { |
| ioList[j].reqNum = j; |
| ioList[j].status = EINPROGRESS; |
| ioList[j].aiocbp = &aiocbList[j]; |
| |
| ioList[j].aiocbp\->aio_fildes = open(argv[j + 1], O_RDONLY); |
| if (ioList[j].aiocbp\->aio_fildes == \-1) |
| errExit("open"); |
| printf("opened %s on descriptor %d\\n", argv[j + 1], |
| ioList[j].aiocbp\->aio_fildes); |
| |
| ioList[j].aiocbp\->aio_buf = malloc(BUF_SIZE); |
| if (ioList[j].aiocbp\->aio_buf == NULL) |
| errExit("malloc"); |
| |
| ioList[j].aiocbp\->aio_nbytes = BUF_SIZE; |
| ioList[j].aiocbp\->aio_reqprio = 0; |
| ioList[j].aiocbp\->aio_offset = 0; |
| ioList[j].aiocbp\->aio_sigevent.sigev_notify = SIGEV_SIGNAL; |
| ioList[j].aiocbp\->aio_sigevent.sigev_signo = IO_SIGNAL; |
| ioList[j].aiocbp\->aio_sigevent.sigev_value.sival_ptr = |
| &ioList[j]; |
| |
| s = aio_read(ioList[j].aiocbp); |
| if (s == \-1) |
| errExit("aio_read"); |
| } |
| |
| openReqs = numReqs; |
| |
| /* Loop, monitoring status of I/O requests */ |
| |
| while (openReqs > 0) { |
| sleep(3); /* Delay between each monitoring step */ |
| |
| if (gotSIGQUIT) { |
| |
| /* On receipt of SIGQUIT, attempt to cancel each of the |
| outstanding I/O requests, and display status returned |
| from the cancellation requests */ |
| |
| printf("got SIGQUIT; canceling I/O requests: \\n"); |
| |
| for (j = 0; j < numReqs; j++) { |
| if (ioList[j].status == EINPROGRESS) { |
| printf(" Request %d on descriptor %d:", j, |
| ioList[j].aiocbp\->aio_fildes); |
| s = aio_cancel(ioList[j].aiocbp\->aio_fildes, |
| ioList[j].aiocbp); |
| if (s == AIO_CANCELED) |
| printf("I/O canceled\\n"); |
| else if (s == AIO_NOTCANCELED) |
| printf("I/O not canceled\\n"); |
| else if (s == AIO_ALLDONE) |
| printf("I/O all done\\n"); |
| else |
| errMsg("aio_cancel"); |
| } |
| } |
| |
| gotSIGQUIT = 0; |
| } |
| |
| /* Check the status of each I/O request that is still |
| in progress */ |
| |
| printf("aio_error():\\n"); |
| for (j = 0; j < numReqs; j++) { |
| if (ioList[j].status == EINPROGRESS) { |
| printf(" for request %d (descriptor %d): ", |
| j, ioList[j].aiocbp\->aio_fildes); |
| ioList[j].status = aio_error(ioList[j].aiocbp); |
| |
| switch (ioList[j].status) { |
| case 0: |
| printf("I/O succeeded\\n"); |
| break; |
| case EINPROGRESS: |
| printf("In progress\\n"); |
| break; |
| case ECANCELED: |
| printf("Canceled\\n"); |
| break; |
| default: |
| errMsg("aio_error"); |
| break; |
| } |
| |
| if (ioList[j].status != EINPROGRESS) |
| openReqs\-\-; |
| } |
| } |
| } |
| |
| printf("All I/O requests completed\\n"); |
| |
| /* Check status return of all I/O requests */ |
| |
| printf("aio_return():\\n"); |
| for (j = 0; j < numReqs; j++) { |
| ssize_t s; |
| |
| s = aio_return(ioList[j].aiocbp); |
| printf(" for request %d (descriptor %d): %zd\\n", |
| j, ioList[j].aiocbp\->aio_fildes, s); |
| } |
| |
| exit(EXIT_SUCCESS); |
| } |
| .fi |
| .SH SEE ALSO |
| .ad l |
| .nh |
| .BR io_cancel (2), |
| .BR io_destroy (2), |
| .BR io_getevents (2), |
| .BR io_setup (2), |
| .BR io_submit (2), |
| .BR aio_cancel (3), |
| .BR aio_error (3), |
| .BR aio_init (3), |
| .BR aio_read (3), |
| .BR aio_return (3), |
| .BR aio_write (3), |
| .BR lio_listio (3) |
| |
| "Asynchronous I/O Support in Linux 2.5", |
| Bhattacharya, Pratt, Pulavarty, and Morgan, |
| Proceedings of the Linux Symposium, 2003, |
| .UR https://www.kernel.org/doc/ols/2003/ols2003\-pages\-351\-366.pdf |
| .UE |