]>
Commit | Line | Data |
---|---|---|
4076f289 MK |
1 | '\" t |
2 | .\" Copyright (c) 2010 by Michael Kerrisk <mtk.manpages@gmail.com> | |
3 | .\" | |
93015253 | 4 | .\" %%%LICENSE_START(VERBATIM) |
4076f289 MK |
5 | .\" Permission is granted to make and distribute verbatim copies of this |
6 | .\" manual provided the copyright notice and this permission notice are | |
7 | .\" preserved on all copies. | |
8 | .\" | |
9 | .\" Permission is granted to copy and distribute modified versions of this | |
10 | .\" manual under the conditions for verbatim copying, provided that the | |
11 | .\" entire resulting derived work is distributed under the terms of a | |
12 | .\" permission notice identical to this one. | |
13 | .\" | |
14 | .\" Since the Linux kernel and libraries are constantly changing, this | |
15 | .\" manual page may be incorrect or out-of-date. The author(s) assume no | |
16 | .\" responsibility for errors or omissions, or for damages resulting from | |
17 | .\" the use of the information contained herein. The author(s) may not | |
18 | .\" have taken the same level of care in the production of this manual, | |
19 | .\" which is licensed free of charge, as they might when working | |
20 | .\" professionally. | |
21 | .\" | |
22 | .\" Formatted or processed versions of this manual, if unaccompanied by | |
23 | .\" the source, must acknowledge the copyright and authors of this work. | |
4b72fb64 | 24 | .\" %%%LICENSE_END |
4076f289 | 25 | .\" |
97986708 | 26 | .TH AIO 7 2016-03-15 "Linux" "Linux Programmer's Manual" |
4076f289 MK |
27 | .SH NAME |
28 | aio \- POSIX asynchronous I/O overview | |
29 | .SH DESCRIPTION | |
30 | The POSIX asynchronous I/O (AIO) interface allows applications | |
31 | to initiate one or more I/O operations that are performed | |
32 | asynchronously (i.e., in the background). | |
33 | The application can elect to be notified of completion of | |
34 | the I/O operation in a variety of ways: | |
35 | by delivery of a signal, by instantiation of a thread, | |
36 | or no notification at all. | |
37 | ||
38 | The POSIX AIO interface consists of the following functions: | |
39 | .TP 16 | |
40 | .BR aio_read (3) | |
41 | Enqueue a read request. | |
42 | This is the asynchronous analog of | |
43 | .BR read (2). | |
44 | .TP | |
45 | .BR aio_write (3) | |
46 | Enqueue a write request. | |
47 | This is the asynchronous analog of | |
48 | .BR write (2). | |
49 | .TP | |
50 | .BR aio_fsync (3) | |
51 | Enqueue a sync request for the I/O operations on a file descriptor. | |
52 | This is the asynchronous analog of | |
53 | .BR fsync (2) | |
54 | and | |
55 | .BR fdatasync (2). | |
56 | .TP | |
57 | .BR aio_error (3) | |
58 | Obtain the error status of an enqueued I/O request. | |
59 | .TP | |
60 | .BR aio_return (3) | |
61 | Obtain the return status of a completed I/O request. | |
62 | .TP | |
63 | .BR aio_suspend (3) | |
64 | Suspend the caller until one or more of a specified set of | |
65 | I/O requests completes. | |
66 | .TP | |
67 | .BR aio_cancel (3) | |
68 | Attempt to cancel outstanding I/O requests on a specified | |
69 | file descriptor. | |
70 | .TP | |
71 | .BR lio_listio (3) | |
72 | Enqueue multiple I/O requests using a single function call. | |
73 | .PP | |
74 | The | |
75 | .I aiocb | |
76 | ("asynchronous I/O control block") structure defines | |
77 | parameters that control an I/O operation. | |
78 | An argument of this type is employed with all of the functions listed above. | |
79 | This structure has the following form: | |
80 | .PP | |
81 | .in +4n | |
82 | .nf | |
83 | #include <aiocb.h> | |
84 | ||
85 | struct aiocb { | |
86 | /* The order of these fields is implementation-dependent */ | |
87 | ||
88 | int aio_fildes; /* File descriptor */ | |
89 | off_t aio_offset; /* File offset */ | |
90 | volatile void *aio_buf; /* Location of buffer */ | |
91 | size_t aio_nbytes; /* Length of transfer */ | |
92 | int aio_reqprio; /* Request priority */ | |
93 | struct sigevent aio_sigevent; /* Notification method */ | |
94 | int aio_lio_opcode; /* Operation to be performed; | |
95 | lio_listio() only */ | |
96 | ||
97 | /* Various implementation-internal fields not shown */ | |
98 | }; | |
99 | ||
836830b4 | 100 | /* Operation codes for \(aqaio_lio_opcode\(aq: */ |
4076f289 MK |
101 | |
102 | enum { LIO_READ, LIO_WRITE, LIO_NOP }; | |
103 | ||
104 | .fi | |
105 | .in | |
106 | The fields of this structure are as follows: | |
107 | .TP 16 | |
108 | .I aio_filedes | |
109 | The file descriptor on which the I/O operation is to be performed. | |
110 | .TP | |
111 | .I aio_offset | |
112 | This is the file offset at which the I/O operation is to be performed. | |
113 | .TP | |
114 | .I aio_buf | |
115 | This is the buffer used to transfer data for a read or write operation. | |
116 | .TP | |
117 | .I aio_nbytes | |
118 | This is the size of the buffer pointed to by | |
119 | .IR aio_buf . | |
120 | .TP | |
121 | .I aio_reqprio | |
122 | This field specifies a value that is subtracted | |
123 | from the calling thread's real-time priority in order to | |
d46da242 | 124 | determine the priority for execution of this I/O request (see |
4076f289 | 125 | .BR pthread_setschedparam (3)). |
59e9285d | 126 | The specified value must be between 0 and the value returned by |
4076f289 | 127 | .IR sysconf(_SC_AIO_PRIO_DELTA_MAX) . |
d46da242 | 128 | This field is ignored for file synchronization operations. |
4076f289 MK |
129 | .TP |
130 | .I aio_sigevent | |
131 | This field is a structure that specifies how the caller is | |
132 | to be notified when the asynchronous I/O operation completes. | |
133 | Possible values for | |
134 | .IR aio_sigevent.sigev_notify | |
135 | are | |
136 | .BR SIGEV_NONE , | |
137 | .BR SIGEV_SIGNAL , | |
138 | and | |
139 | .BR SIGEV_THREAD . | |
140 | See | |
141 | .BR sigevent (7) | |
142 | for further details. | |
143 | .TP | |
144 | .I aio_lio_opcode | |
145 | The type of operation to be performed; used only for | |
146 | .BR lio_listio (3). | |
147 | .PP | |
148 | In addition to the standard functions listed above, | |
149 | the GNU C library provides the following extension to the POSIX AIO API: | |
150 | .TP 16 | |
151 | .BR aio_init (3) | |
152 | Set parameters for tuning the behavior of the glibc POSIX AIO implementation. | |
7484d5a7 MK |
153 | .SH ERRORS |
154 | .TP | |
155 | .B EINVAL | |
156 | The | |
157 | .I aio_reqprio | |
158 | field of the | |
159 | .I aiocb | |
160 | structure was less than 0, | |
161 | or was greater than the limit returned by the call | |
162 | .IR sysconf(_SC_AIO_PRIO_DELTA_MAX) . | |
163 | .SH VERSIONS | |
164 | The POSIX AIO interfaces are provided by glibc since version 2.1. | |
165 | .SH CONFORMING TO | |
166 | POSIX.1-2001, POSIX.1-2008. | |
4076f289 MK |
167 | .SH NOTES |
168 | It is a good idea to zero out the control block buffer before use (see | |
169 | .BR memset (3)). | |
170 | The control block buffer and the buffer pointed to by | |
171 | .I aio_buf | |
172 | must not be changed while the I/O operation is in progress. | |
173 | These buffers must remain valid until the I/O operation completes. | |
174 | ||
175 | Simultaneous asynchronous read or write operations using the same | |
176 | .I aiocb | |
177 | structure yield undefined results. | |
178 | ||
7fac88a9 | 179 | The current Linux POSIX AIO implementation is provided in user space by glibc. |
4076f289 MK |
180 | This has a number of limitations, most notably that maintaining multiple |
181 | threads to perform I/O operations is expensive and scales poorly. | |
182 | Work has been in progress for some time on a kernel | |
183 | state-machine-based implementation of asynchronous I/O | |
184 | (see | |
185 | .BR io_submit (2), | |
186 | .BR io_setup (2), | |
187 | .BR io_cancel (2), | |
188 | .BR io_destroy (2), | |
189 | .BR io_getevents (2)), | |
190 | but this implementation hasn't yet matured to the point where | |
191 | the POSIX AIO implementation can be completely | |
192 | reimplemented using the kernel system calls. | |
193 | .\" http://lse.sourceforge.net/io/aio.html | |
194 | .\" http://lse.sourceforge.net/io/aionotes.txt | |
195 | .\" http://lwn.net/Articles/148755/ | |
4076f289 MK |
196 | .SH EXAMPLE |
197 | The program below opens each of the files named in its command-line | |
198 | arguments and queues a request on the resulting file descriptor using | |
199 | .BR aio_read (3). | |
200 | The program then loops, | |
201 | periodically monitoring each of the I/O operations | |
202 | that is still in progress using | |
203 | .BR aio_error (3). | |
204 | Each of the I/O requests is set up to provide notification by delivery | |
205 | of a signal. | |
206 | After all I/O requests have completed, | |
207 | the program retrieves their status using | |
208 | .BR aio_return (3). | |
209 | ||
210 | The | |
211 | .B SIGQUIT | |
212 | signal (generated by typing control-\\) causes the program to request | |
213 | cancellation of each of the outstanding requests using | |
214 | .BR aio_cancel (3). | |
215 | ||
216 | Here is an example of what we might see when running this program. | |
217 | In this example, the program queues two requests to standard input, | |
218 | and these are satisfied by two lines of input containing | |
219 | "abc" and "x". | |
220 | ||
221 | .in +4n | |
222 | .nf | |
223 | $ \fB./a.out /dev/stdin /dev/stdin\fP | |
224 | opened /dev/stdin on descriptor 3 | |
225 | opened /dev/stdin on descriptor 4 | |
226 | aio_error(): | |
227 | for request 0 (descriptor 3): In progress | |
228 | for request 1 (descriptor 4): In progress | |
229 | \fBabc\fP | |
230 | I/O completion signal received | |
231 | aio_error(): | |
232 | for request 0 (descriptor 3): I/O succeeded | |
233 | for request 1 (descriptor 4): In progress | |
234 | aio_error(): | |
235 | for request 1 (descriptor 4): In progress | |
236 | \fBx\fP | |
237 | I/O completion signal received | |
238 | aio_error(): | |
239 | for request 1 (descriptor 4): I/O succeeded | |
240 | All I/O requests completed | |
241 | aio_return(): | |
242 | for request 0 (descriptor 3): 4 | |
243 | for request 1 (descriptor 4): 2 | |
244 | .fi | |
245 | .in | |
246 | .SS Program source | |
247 | \& | |
248 | .nf | |
ce108729 | 249 | #include <fcntl.h> |
4076f289 MK |
250 | #include <stdlib.h> |
251 | #include <unistd.h> | |
252 | #include <stdio.h> | |
253 | #include <errno.h> | |
254 | #include <aio.h> | |
255 | #include <signal.h> | |
256 | ||
257 | #define BUF_SIZE 20 /* Size of buffers for read operations */ | |
258 | ||
259 | #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) | |
260 | ||
261 | #define errMsg(msg) do { perror(msg); } while (0) | |
262 | ||
263 | struct ioRequest { /* Application\-defined structure for tracking | |
264 | I/O requests */ | |
265 | int reqNum; | |
266 | int status; | |
267 | struct aiocb *aiocbp; | |
268 | }; | |
269 | ||
270 | static volatile sig_atomic_t gotSIGQUIT = 0; | |
271 | /* On delivery of SIGQUIT, we attempt to | |
272 | cancel all outstanding I/O requests */ | |
273 | ||
274 | static void /* Handler for SIGQUIT */ | |
275 | quitHandler(int sig) | |
276 | { | |
277 | gotSIGQUIT = 1; | |
278 | } | |
279 | ||
280 | #define IO_SIGNAL SIGUSR1 /* Signal used to notify I/O completion */ | |
281 | ||
282 | static void /* Handler for I/O completion signal */ | |
283 | aioSigHandler(int sig, siginfo_t *si, void *ucontext) | |
284 | { | |
148c6e74 AG |
285 | if (si->si_code == SI_ASYNCIO) { |
286 | write(STDOUT_FILENO, "I/O completion signal received\\n", 31); | |
4076f289 | 287 | |
148c6e74 AG |
288 | /* The corresponding ioRequest structure would be available as |
289 | struct ioRequest *ioReq = si\->si_value.sival_ptr; | |
290 | and the file descriptor would then be available via | |
291 | ioReq\->aiocbp\->aio_fildes */ | |
292 | } | |
4076f289 MK |
293 | } |
294 | ||
295 | int | |
296 | main(int argc, char *argv[]) | |
297 | { | |
298 | struct ioRequest *ioList; | |
299 | struct aiocb *aiocbList; | |
300 | struct sigaction sa; | |
301 | int s, j; | |
302 | int numReqs; /* Total number of queued I/O requests */ | |
303 | int openReqs; /* Number of I/O requests still in progress */ | |
304 | ||
305 | if (argc < 2) { | |
306 | fprintf(stderr, "Usage: %s <pathname> <pathname>...\\n", | |
307 | argv[0]); | |
308 | exit(EXIT_FAILURE); | |
309 | } | |
310 | ||
311 | numReqs = argc \- 1; | |
312 | ||
313 | /* Allocate our arrays */ | |
314 | ||
315 | ioList = calloc(numReqs, sizeof(struct ioRequest)); | |
316 | if (ioList == NULL) | |
317 | errExit("calloc"); | |
318 | ||
319 | aiocbList = calloc(numReqs, sizeof(struct aiocb)); | |
320 | if (aiocbList == NULL) | |
321 | errExit("calloc"); | |
322 | ||
323 | /* Establish handlers for SIGQUIT and the I/O completion signal */ | |
324 | ||
325 | sa.sa_flags = SA_RESTART; | |
326 | sigemptyset(&sa.sa_mask); | |
327 | ||
328 | sa.sa_handler = quitHandler; | |
329 | if (sigaction(SIGQUIT, &sa, NULL) == \-1) | |
330 | errExit("sigaction"); | |
331 | ||
332 | sa.sa_flags = SA_RESTART | SA_SIGINFO; | |
333 | sa.sa_sigaction = aioSigHandler; | |
334 | if (sigaction(IO_SIGNAL, &sa, NULL) == \-1) | |
335 | errExit("sigaction"); | |
336 | ||
337 | /* Open each file specified on the command line, and queue | |
338 | a read request on the resulting file descriptor */ | |
339 | ||
340 | for (j = 0; j < numReqs; j++) { | |
341 | ioList[j].reqNum = j; | |
342 | ioList[j].status = EINPROGRESS; | |
343 | ioList[j].aiocbp = &aiocbList[j]; | |
344 | ||
345 | ioList[j].aiocbp\->aio_fildes = open(argv[j + 1], O_RDONLY); | |
346 | if (ioList[j].aiocbp\->aio_fildes == \-1) | |
347 | errExit("open"); | |
348 | printf("opened %s on descriptor %d\\n", argv[j + 1], | |
349 | ioList[j].aiocbp\->aio_fildes); | |
350 | ||
351 | ioList[j].aiocbp\->aio_buf = malloc(BUF_SIZE); | |
352 | if (ioList[j].aiocbp\->aio_buf == NULL) | |
353 | errExit("malloc"); | |
354 | ||
355 | ioList[j].aiocbp\->aio_nbytes = BUF_SIZE; | |
356 | ioList[j].aiocbp\->aio_reqprio = 0; | |
357 | ioList[j].aiocbp\->aio_offset = 0; | |
358 | ioList[j].aiocbp\->aio_sigevent.sigev_notify = SIGEV_SIGNAL; | |
359 | ioList[j].aiocbp\->aio_sigevent.sigev_signo = IO_SIGNAL; | |
360 | ioList[j].aiocbp\->aio_sigevent.sigev_value.sival_ptr = | |
361 | &ioList[j]; | |
362 | ||
363 | s = aio_read(ioList[j].aiocbp); | |
364 | if (s == \-1) | |
365 | errExit("aio_read"); | |
366 | } | |
367 | ||
368 | openReqs = numReqs; | |
369 | ||
370 | /* Loop, monitoring status of I/O requests */ | |
371 | ||
372 | while (openReqs > 0) { | |
373 | sleep(3); /* Delay between each monitoring step */ | |
374 | ||
375 | if (gotSIGQUIT) { | |
376 | ||
377 | /* On receipt of SIGQUIT, attempt to cancel each of the | |
378 | outstanding I/O requests, and display status returned | |
379 | from the cancellation requests */ | |
380 | ||
381 | printf("got SIGQUIT; canceling I/O requests: \\n"); | |
382 | ||
383 | for (j = 0; j < numReqs; j++) { | |
384 | if (ioList[j].status == EINPROGRESS) { | |
385 | printf(" Request %d on descriptor %d:", j, | |
386 | ioList[j].aiocbp\->aio_fildes); | |
387 | s = aio_cancel(ioList[j].aiocbp\->aio_fildes, | |
388 | ioList[j].aiocbp); | |
389 | if (s == AIO_CANCELED) | |
390 | printf("I/O canceled\\n"); | |
391 | else if (s == AIO_NOTCANCELED) | |
392 | printf("I/O not canceled\\n"); | |
393 | else if (s == AIO_ALLDONE) | |
394 | printf("I/O all done\\n"); | |
395 | else | |
396 | errMsg("aio_cancel"); | |
397 | } | |
398 | } | |
399 | ||
400 | gotSIGQUIT = 0; | |
401 | } | |
402 | ||
403 | /* Check the status of each I/O request that is still | |
404 | in progress */ | |
405 | ||
406 | printf("aio_error():\\n"); | |
407 | for (j = 0; j < numReqs; j++) { | |
408 | if (ioList[j].status == EINPROGRESS) { | |
409 | printf(" for request %d (descriptor %d): ", | |
410 | j, ioList[j].aiocbp\->aio_fildes); | |
411 | ioList[j].status = aio_error(ioList[j].aiocbp); | |
412 | ||
413 | switch (ioList[j].status) { | |
414 | case 0: | |
415 | printf("I/O succeeded\\n"); | |
416 | break; | |
417 | case EINPROGRESS: | |
418 | printf("In progress\\n"); | |
419 | break; | |
420 | case ECANCELED: | |
421 | printf("Canceled\\n"); | |
422 | break; | |
423 | default: | |
424 | errMsg("aio_error"); | |
425 | break; | |
426 | } | |
427 | ||
428 | if (ioList[j].status != EINPROGRESS) | |
429 | openReqs\-\-; | |
430 | } | |
431 | } | |
432 | } | |
433 | ||
434 | printf("All I/O requests completed\\n"); | |
435 | ||
436 | /* Check status return of all I/O requests */ | |
437 | ||
438 | printf("aio_return():\\n"); | |
439 | for (j = 0; j < numReqs; j++) { | |
440 | ssize_t s; | |
441 | ||
442 | s = aio_return(ioList[j].aiocbp); | |
8c5fcd21 MK |
443 | printf(" for request %d (descriptor %d): %zd\\n", |
444 | j, ioList[j].aiocbp\->aio_fildes, s); | |
4076f289 MK |
445 | } |
446 | ||
447 | exit(EXIT_SUCCESS); | |
448 | } | |
449 | .fi | |
450 | .SH SEE ALSO | |
451 | .ad l | |
ca8a0bd2 | 452 | .nh |
4076f289 MK |
453 | .BR io_cancel (2), |
454 | .BR io_destroy (2), | |
95406ae0 | 455 | .BR io_getevents (2), |
3e5c319e MK |
456 | .BR io_setup (2), |
457 | .BR io_submit (2), | |
4076f289 MK |
458 | .BR aio_cancel (3), |
459 | .BR aio_error (3), | |
460 | .BR aio_init (3), | |
461 | .BR aio_read (3), | |
462 | .BR aio_return (3), | |
463 | .BR aio_write (3), | |
173fe7e7 DP |
464 | .BR lio_listio (3) |
465 | ||
692ed9b6 MK |
466 | "Asynchronous I/O Support in Linux 2.5", |
467 | Bhattacharya, Pratt, Pulavarty, and Morgan, | |
468 | Proceedings of the Linux Symposium, 2003, | |
469 | .UR https://www.kernel.org/doc/ols/2003/ols2003-pages-351-366.pdf | |
608bf950 | 470 | .UE |