1AIO(7) Linux Programmer's Manual AIO(7)
2
3
4
6 aio - POSIX asynchronous I/O overview
7
9 The POSIX asynchronous I/O (AIO) interface allows applications to ini‐
10 tiate one or more I/O operations that are performed asynchronously
11 (i.e., in the background). The application can elect to be notified of
12 completion of the I/O operation in a variety of ways: by delivery of a
13 signal, by instantiation of a thread, or no notification at all.
14
15 The POSIX AIO interface consists of the following functions:
16
17 aio_read(3) Enqueue a read request. This is the asynchronous ana‐
18 log of read(2).
19
20 aio_write(3) Enqueue a write request. This is the asynchronous ana‐
21 log of write(2).
22
23 aio_fsync(3) Enqueue a sync request for the I/O operations on a file
24 descriptor. This is the asynchronous analog of
25 fsync(2) and fdatasync(2).
26
27 aio_error(3) Obtain the error status of an enqueued I/O request.
28
29 aio_return(3) Obtain the return status of a completed I/O request.
30
31 aio_suspend(3) Suspend the caller until one or more of a specified set
32 of I/O requests completes.
33
34 aio_cancel(3) Attempt to cancel outstanding I/O requests on a speci‐
35 fied file descriptor.
36
37 lio_listio(3) Enqueue multiple I/O requests using a single function
38 call.
39
40 The aiocb ("asynchronous I/O control block") structure defines parame‐
41 ters that control an I/O operation. An argument of this type is
42 employed with all of the functions listed above. This structure has
43 the following form:
44
45 #include <aiocb.h>
46
47 struct aiocb {
48 /* The order of these fields is implementation-dependent */
49
50 int aio_fildes; /* File descriptor */
51 off_t aio_offset; /* File offset */
52 volatile void *aio_buf; /* Location of buffer */
53 size_t aio_nbytes; /* Length of transfer */
54 int aio_reqprio; /* Request priority */
55 struct sigevent aio_sigevent; /* Notification method */
56 int aio_lio_opcode; /* Operation to be performed;
57 lio_listio() only */
58
59 /* Various implementation-internal fields not shown */
60 };
61
62 /* Operation codes for 'aio_lio_opcode': */
63
64 enum { LIO_READ, LIO_WRITE, LIO_NOP };
65
66 The fields of this structure are as follows:
67
68 aio_fildes The file descriptor on which the I/O operation is to be
69 performed.
70
71 aio_offset This is the file offset at which the I/O operation is
72 to be performed.
73
74 aio_buf This is the buffer used to transfer data for a read or
75 write operation.
76
77 aio_nbytes This is the size of the buffer pointed to by aio_buf.
78
79 aio_reqprio This field specifies a value that is subtracted from
80 the calling thread's real-time priority in order to
81 determine the priority for execution of this I/O
82 request (see pthread_setschedparam(3)). The specified
83 value must be between 0 and the value returned by
84 sysconf(_SC_AIO_PRIO_DELTA_MAX). This field is ignored
85 for file synchronization operations.
86
87 aio_sigevent This field is a structure that specifies how the caller
88 is to be notified when the asynchronous I/O operation
89 completes. Possible values for
90 aio_sigevent.sigev_notify are SIGEV_NONE, SIGEV_SIGNAL,
91 and SIGEV_THREAD. See sigevent(7) for further details.
92
93 aio_lio_opcode The type of operation to be performed; used only for
94 lio_listio(3).
95
96 In addition to the standard functions listed above, the GNU C library
97 provides the following extension to the POSIX AIO API:
98
99 aio_init(3) Set parameters for tuning the behavior of the glibc
100 POSIX AIO implementation.
101
103 EINVAL The aio_reqprio field of the aiocb structure was less than 0, or
104 was greater than the limit returned by the call
105 sysconf(_SC_AIO_PRIO_DELTA_MAX).
106
108 The POSIX AIO interfaces are provided by glibc since version 2.1.
109
111 POSIX.1-2001, POSIX.1-2008.
112
114 It is a good idea to zero out the control block buffer before use (see
115 memset(3)). The control block buffer and the buffer pointed to by
116 aio_buf must not be changed while the I/O operation is in progress.
117 These buffers must remain valid until the I/O operation completes.
118
119 Simultaneous asynchronous read or write operations using the same aiocb
120 structure yield undefined results.
121
122 The current Linux POSIX AIO implementation is provided in user space by
123 glibc. This has a number of limitations, most notably that maintaining
124 multiple threads to perform I/O operations is expensive and scales
125 poorly. Work has been in progress for some time on a kernel state-
126 machine-based implementation of asynchronous I/O (see io_submit(2),
127 io_setup(2), io_cancel(2), io_destroy(2), io_getevents(2)), but this
128 implementation hasn't yet matured to the point where the POSIX AIO
129 implementation can be completely reimplemented using the kernel system
130 calls.
131
133 The program below opens each of the files named in its command-line
134 arguments and queues a request on the resulting file descriptor using
135 aio_read(3). The program then loops, periodically monitoring each of
136 the I/O operations that is still in progress using aio_error(3). Each
137 of the I/O requests is set up to provide notification by delivery of a
138 signal. After all I/O requests have completed, the program retrieves
139 their status using aio_return(3).
140
141 The SIGQUIT signal (generated by typing control-\) causes the program
142 to request cancellation of each of the outstanding requests using
143 aio_cancel(3).
144
145 Here is an example of what we might see when running this program. In
146 this example, the program queues two requests to standard input, and
147 these are satisfied by two lines of input containing "abc" and "x".
148
149 $ ./a.out /dev/stdin /dev/stdin
150 opened /dev/stdin on descriptor 3
151 opened /dev/stdin on descriptor 4
152 aio_error():
153 for request 0 (descriptor 3): In progress
154 for request 1 (descriptor 4): In progress
155 abc
156 I/O completion signal received
157 aio_error():
158 for request 0 (descriptor 3): I/O succeeded
159 for request 1 (descriptor 4): In progress
160 aio_error():
161 for request 1 (descriptor 4): In progress
162 x
163 I/O completion signal received
164 aio_error():
165 for request 1 (descriptor 4): I/O succeeded
166 All I/O requests completed
167 aio_return():
168 for request 0 (descriptor 3): 4
169 for request 1 (descriptor 4): 2
170
171 Program source
172
173 #include <fcntl.h>
174 #include <stdlib.h>
175 #include <unistd.h>
176 #include <stdio.h>
177 #include <errno.h>
178 #include <aio.h>
179 #include <signal.h>
180
181 #define BUF_SIZE 20 /* Size of buffers for read operations */
182
183 #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
184
185 #define errMsg(msg) do { perror(msg); } while (0)
186
187 struct ioRequest { /* Application-defined structure for tracking
188 I/O requests */
189 int reqNum;
190 int status;
191 struct aiocb *aiocbp;
192 };
193
194 static volatile sig_atomic_t gotSIGQUIT = 0;
195 /* On delivery of SIGQUIT, we attempt to
196 cancel all outstanding I/O requests */
197
198 static void /* Handler for SIGQUIT */
199 quitHandler(int sig)
200 {
201 gotSIGQUIT = 1;
202 }
203
204 #define IO_SIGNAL SIGUSR1 /* Signal used to notify I/O completion */
205
206 static void /* Handler for I/O completion signal */
207 aioSigHandler(int sig, siginfo_t *si, void *ucontext)
208 {
209 if (si->si_code == SI_ASYNCIO) {
210 write(STDOUT_FILENO, "I/O completion signal received\n", 31);
211
212 /* The corresponding ioRequest structure would be available as
213 struct ioRequest *ioReq = si->si_value.sival_ptr;
214 and the file descriptor would then be available via
215 ioReq->aiocbp->aio_fildes */
216 }
217 }
218
219 int
220 main(int argc, char *argv[])
221 {
222 struct ioRequest *ioList;
223 struct aiocb *aiocbList;
224 struct sigaction sa;
225 int s, j;
226 int numReqs; /* Total number of queued I/O requests */
227 int openReqs; /* Number of I/O requests still in progress */
228
229 if (argc < 2) {
230 fprintf(stderr, "Usage: %s <pathname> <pathname>...\n",
231 argv[0]);
232 exit(EXIT_FAILURE);
233 }
234
235 numReqs = argc - 1;
236
237 /* Allocate our arrays */
238
239 ioList = calloc(numReqs, sizeof(struct ioRequest));
240 if (ioList == NULL)
241 errExit("calloc");
242
243 aiocbList = calloc(numReqs, sizeof(struct aiocb));
244 if (aiocbList == NULL)
245 errExit("calloc");
246
247 /* Establish handlers for SIGQUIT and the I/O completion signal */
248
249 sa.sa_flags = SA_RESTART;
250 sigemptyset(&sa.sa_mask);
251
252 sa.sa_handler = quitHandler;
253 if (sigaction(SIGQUIT, &sa, NULL) == -1)
254 errExit("sigaction");
255
256 sa.sa_flags = SA_RESTART | SA_SIGINFO;
257 sa.sa_sigaction = aioSigHandler;
258 if (sigaction(IO_SIGNAL, &sa, NULL) == -1)
259 errExit("sigaction");
260
261 /* Open each file specified on the command line, and queue
262 a read request on the resulting file descriptor */
263
264 for (j = 0; j < numReqs; j++) {
265 ioList[j].reqNum = j;
266 ioList[j].status = EINPROGRESS;
267 ioList[j].aiocbp = &aiocbList[j];
268
269 ioList[j].aiocbp->aio_fildes = open(argv[j + 1], O_RDONLY);
270 if (ioList[j].aiocbp->aio_fildes == -1)
271 errExit("open");
272 printf("opened %s on descriptor %d\n", argv[j + 1],
273 ioList[j].aiocbp->aio_fildes);
274
275 ioList[j].aiocbp->aio_buf = malloc(BUF_SIZE);
276 if (ioList[j].aiocbp->aio_buf == NULL)
277 errExit("malloc");
278
279 ioList[j].aiocbp->aio_nbytes = BUF_SIZE;
280 ioList[j].aiocbp->aio_reqprio = 0;
281 ioList[j].aiocbp->aio_offset = 0;
282 ioList[j].aiocbp->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
283 ioList[j].aiocbp->aio_sigevent.sigev_signo = IO_SIGNAL;
284 ioList[j].aiocbp->aio_sigevent.sigev_value.sival_ptr =
285 &ioList[j];
286
287 s = aio_read(ioList[j].aiocbp);
288 if (s == -1)
289 errExit("aio_read");
290 }
291
292 openReqs = numReqs;
293
294 /* Loop, monitoring status of I/O requests */
295
296 while (openReqs > 0) {
297 sleep(3); /* Delay between each monitoring step */
298
299 if (gotSIGQUIT) {
300
301 /* On receipt of SIGQUIT, attempt to cancel each of the
302 outstanding I/O requests, and display status returned
303 from the cancellation requests */
304
305 printf("got SIGQUIT; canceling I/O requests: \n");
306
307 for (j = 0; j < numReqs; j++) {
308 if (ioList[j].status == EINPROGRESS) {
309 printf(" Request %d on descriptor %d:", j,
310 ioList[j].aiocbp->aio_fildes);
311 s = aio_cancel(ioList[j].aiocbp->aio_fildes,
312 ioList[j].aiocbp);
313 if (s == AIO_CANCELED)
314 printf("I/O canceled\n");
315 else if (s == AIO_NOTCANCELED)
316 printf("I/O not canceled\n");
317 else if (s == AIO_ALLDONE)
318 printf("I/O all done\n");
319 else
320 errMsg("aio_cancel");
321 }
322 }
323
324 gotSIGQUIT = 0;
325 }
326
327 /* Check the status of each I/O request that is still
328 in progress */
329
330 printf("aio_error():\n");
331 for (j = 0; j < numReqs; j++) {
332 if (ioList[j].status == EINPROGRESS) {
333 printf(" for request %d (descriptor %d): ",
334 j, ioList[j].aiocbp->aio_fildes);
335 ioList[j].status = aio_error(ioList[j].aiocbp);
336
337 switch (ioList[j].status) {
338 case 0:
339 printf("I/O succeeded\n");
340 break;
341 case EINPROGRESS:
342 printf("In progress\n");
343 break;
344 case ECANCELED:
345 printf("Canceled\n");
346 break;
347 default:
348 errMsg("aio_error");
349 break;
350 }
351
352 if (ioList[j].status != EINPROGRESS)
353 openReqs--;
354 }
355 }
356 }
357
358 printf("All I/O requests completed\n");
359
360 /* Check status return of all I/O requests */
361
362 printf("aio_return():\n");
363 for (j = 0; j < numReqs; j++) {
364 ssize_t s;
365
366 s = aio_return(ioList[j].aiocbp);
367 printf(" for request %d (descriptor %d): %zd\n",
368 j, ioList[j].aiocbp->aio_fildes, s);
369 }
370
371 exit(EXIT_SUCCESS);
372 }
373
375 io_cancel(2), io_destroy(2), io_getevents(2), io_setup(2),
376 io_submit(2), aio_cancel(3), aio_error(3), aio_init(3), aio_read(3),
377 aio_return(3), aio_write(3), lio_listio(3)
378
379 "Asynchronous I/O Support in Linux 2.5", Bhattacharya, Pratt,
380 Pulavarty, and Morgan, Proceedings of the Linux Symposium, 2003,
381 ⟨https://www.kernel.org/doc/ols/2003/ols2003-pages-351-366.pdf⟩
382
384 This page is part of release 4.15 of the Linux man-pages project. A
385 description of the project, information about reporting bugs, and the
386 latest version of this page, can be found at
387 https://www.kernel.org/doc/man-pages/.
388
389
390
391Linux 2017-09-15 AIO(7)