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