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