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_filedes 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 <stdlib.h>
174 #include <unistd.h>
175 #include <stdio.h>
176 #include <errno.h>
177 #include <aio.h>
178 #include <signal.h>
179
180 #define BUF_SIZE 20 /* Size of buffers for read operations */
181
182 #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
183
184 #define errMsg(msg) do { perror(msg); } while (0)
185
186 struct ioRequest { /* Application-defined structure for tracking
187 I/O requests */
188 int reqNum;
189 int status;
190 struct aiocb *aiocbp;
191 };
192
193 static volatile sig_atomic_t gotSIGQUIT = 0;
194 /* On delivery of SIGQUIT, we attempt to
195 cancel all outstanding I/O requests */
196
197 static void /* Handler for SIGQUIT */
198 quitHandler(int sig)
199 {
200 gotSIGQUIT = 1;
201 }
202
203 #define IO_SIGNAL SIGUSR1 /* Signal used to notify I/O completion */
204
205 static void /* Handler for I/O completion signal */
206 aioSigHandler(int sig, siginfo_t *si, void *ucontext)
207 {
208 write(STDOUT_FILENO, "I/O completion signal received\n", 31);
209
210 /* The corresponding ioRequest structure would be available as
211 struct ioRequest *ioReq = si->si_value.sival_ptr;
212 and the file descriptor would then be available via
213 ioReq->aiocbp->aio_fildes */
214 }
215
216 int
217 main(int argc, char *argv[])
218 {
219 struct ioRequest *ioList;
220 struct aiocb *aiocbList;
221 struct sigaction sa;
222 int s, j;
223 int numReqs; /* Total number of queued I/O requests */
224 int openReqs; /* Number of I/O requests still in progress */
225
226 if (argc < 2) {
227 fprintf(stderr, "Usage: %s <pathname> <pathname>...\n",
228 argv[0]);
229 exit(EXIT_FAILURE);
230 }
231
232 numReqs = argc - 1;
233
234 /* Allocate our arrays */
235
236 ioList = calloc(numReqs, sizeof(struct ioRequest));
237 if (ioList == NULL)
238 errExit("calloc");
239
240 aiocbList = calloc(numReqs, sizeof(struct aiocb));
241 if (aiocbList == NULL)
242 errExit("calloc");
243
244 /* Establish handlers for SIGQUIT and the I/O completion signal */
245
246 sa.sa_flags = SA_RESTART;
247 sigemptyset(&sa.sa_mask);
248
249 sa.sa_handler = quitHandler;
250 if (sigaction(SIGQUIT, &sa, NULL) == -1)
251 errExit("sigaction");
252
253 sa.sa_flags = SA_RESTART | SA_SIGINFO;
254 sa.sa_sigaction = aioSigHandler;
255 if (sigaction(IO_SIGNAL, &sa, NULL) == -1)
256 errExit("sigaction");
257
258 /* Open each file specified on the command line, and queue
259 a read request on the resulting file descriptor */
260
261 for (j = 0; j < numReqs; j++) {
262 ioList[j].reqNum = j;
263 ioList[j].status = EINPROGRESS;
264 ioList[j].aiocbp = &aiocbList[j];
265
266 ioList[j].aiocbp->aio_fildes = open(argv[j + 1], O_RDONLY);
267 if (ioList[j].aiocbp->aio_fildes == -1)
268 errExit("open");
269 printf("opened %s on descriptor %d\n", argv[j + 1],
270 ioList[j].aiocbp->aio_fildes);
271
272 ioList[j].aiocbp->aio_buf = malloc(BUF_SIZE);
273 if (ioList[j].aiocbp->aio_buf == NULL)
274 errExit("malloc");
275
276 ioList[j].aiocbp->aio_nbytes = BUF_SIZE;
277 ioList[j].aiocbp->aio_reqprio = 0;
278 ioList[j].aiocbp->aio_offset = 0;
279 ioList[j].aiocbp->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
280 ioList[j].aiocbp->aio_sigevent.sigev_signo = IO_SIGNAL;
281 ioList[j].aiocbp->aio_sigevent.sigev_value.sival_ptr =
282 &ioList[j];
283
284 s = aio_read(ioList[j].aiocbp);
285 if (s == -1)
286 errExit("aio_read");
287 }
288
289 openReqs = numReqs;
290
291 /* Loop, monitoring status of I/O requests */
292
293 while (openReqs > 0) {
294 sleep(3); /* Delay between each monitoring step */
295
296 if (gotSIGQUIT) {
297
298 /* On receipt of SIGQUIT, attempt to cancel each of the
299 outstanding I/O requests, and display status returned
300 from the cancellation requests */
301
302 printf("got SIGQUIT; canceling I/O requests: \n");
303
304 for (j = 0; j < numReqs; j++) {
305 if (ioList[j].status == EINPROGRESS) {
306 printf(" Request %d on descriptor %d:", j,
307 ioList[j].aiocbp->aio_fildes);
308 s = aio_cancel(ioList[j].aiocbp->aio_fildes,
309 ioList[j].aiocbp);
310 if (s == AIO_CANCELED)
311 printf("I/O canceled\n");
312 else if (s == AIO_NOTCANCELED)
313 printf("I/O not canceled\n");
314 else if (s == AIO_ALLDONE)
315 printf("I/O all done\n");
316 else
317 errMsg("aio_cancel");
318 }
319 }
320
321 gotSIGQUIT = 0;
322 }
323
324 /* Check the status of each I/O request that is still
325 in progress */
326
327 printf("aio_error():\n");
328 for (j = 0; j < numReqs; j++) {
329 if (ioList[j].status == EINPROGRESS) {
330 printf(" for request %d (descriptor %d): ",
331 j, ioList[j].aiocbp->aio_fildes);
332 ioList[j].status = aio_error(ioList[j].aiocbp);
333
334 switch (ioList[j].status) {
335 case 0:
336 printf("I/O succeeded\n");
337 break;
338 case EINPROGRESS:
339 printf("In progress\n");
340 break;
341 case ECANCELED:
342 printf("Canceled\n");
343 break;
344 default:
345 errMsg("aio_error");
346 break;
347 }
348
349 if (ioList[j].status != EINPROGRESS)
350 openReqs--;
351 }
352 }
353 }
354
355 printf("All I/O requests completed\n");
356
357 /* Check status return of all I/O requests */
358
359 printf("aio_return():\n");
360 for (j = 0; j < numReqs; j++) {
361 ssize_t s;
362
363 s = aio_return(ioList[j].aiocbp);
364 printf(" for request %d (descriptor %d): %ld\n",
365 j, ioList[j].aiocbp->aio_fildes, (long) s);
366 }
367
368 exit(EXIT_SUCCESS);
369 }
370
372 io_cancel(2), io_destroy(2), io_getevents(2), io_setup(2),
373 io_submit(2), aio_cancel(3), aio_error(3), aio_init(3), aio_read(3),
374 aio_return(3), aio_write(3), lio_listio(3)
375
376 ⟨http://www.squid-cache.org/~adrian/Reprint-Pulavarty-OLS2003.pdf⟩
377
379 This page is part of release 3.53 of the Linux man-pages project. A
380 description of the project, and information about reporting bugs, can
381 be found at http://www.kernel.org/doc/man-pages/.
382
383
384
385Linux 2012-08-05 AIO(7)