2 .\" Copyright (c) 2010 by Michael Kerrisk <mtk.manpages@gmail.com>
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.
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.
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
21 .\" Formatted or processed versions of this manual, if unaccompanied by
22 .\" the source, must acknowledge the copyright and authors of this work.
24 .\"*******************************************************************
26 .\" This file was generated with po4a. Translate the source file.
28 .\"*******************************************************************
29 .TH AIO 7 2010\-10\-02 Linux "Linux Programmer's Manual"
31 aio \- POSIX 非同期 I/O の概要
33 POSIX 非同期 (AIO) インターフェースを使うと、アプリケーションは、非同期
34 に (つまり、バックグラウンドで) 実行されるI/O 操作を一つ以上発行できる
35 ようになる。アプリケーションは I/O 操作の完了の通知方法を選択することが
36 できる。選択できる通知方法は、シグナルの配送、スレッドの起動、通知を行
39 POSIX AIO インターフェースは以下の関数で構成されている。
43 \fBread\fP(2) の非同期版である。
47 \fBwrite\fP(2) の非同期版である。
50 ファイルディスクリプタに対して行われた I/O 操作の
51 同期 (sync) リクエストをキューに入れる。
52 \fBfsync\fP(2) や \fBfdatasync\fP(2) の非同期版である。
55 キューに入れられた I/O リクエストのエラー状態を取得する。
58 完了した I/O リクエストの終了ステータスを取得する。
61 指定された I/O リクエストの集合 (要素は一つ以上) が完了するまで、
62 呼び出し側の実行を停止 (suspend) する。
66 完了していない I/O リクエストのキャンセルを試みる。
69 一回の関数呼び出しで複数の I/O リクエストをキューに入れる。
71 \fIaiocb\fP ("非同期 I/O 制御ブロック (asynchronous I/O control block)")
72 構造体は、I/O 操作を制御するパラメータを定義する。この型の引き数は上記
73 の全ての関数で使用されている。この構造体は以下の通りである。
80 /* The order of these fields is implementation\-dependent */
82 int aio_fildes; /* File descriptor */
83 off_t aio_offset; /* File offset */
84 volatile void *aio_buf; /* Location of buffer */
85 size_t aio_nbytes; /* Length of transfer */
86 int aio_reqprio; /* Request priority */
87 struct sigevent aio_sigevent; /* Notification method */
88 int aio_lio_opcode; /* Operation to be performed;
91 /* Various implementation\-internal fields not shown */
94 /* Operation codes for \(aqaio_lio_opcode\(aq: */
96 enum { LIO_READ, LIO_WRITE, LIO_NOP };
100 この構造体のフィールドは以下の通りである。
103 I/O 操作の実行対象となるファイルディスクリプタ。
106 I/O 操作を行うファイルオフセットを示す。
109 読み出し操作、書き込み操作でデータ転送に使用されるバッファ。
112 \fIaio_buf\fP が指すバッファのサイズ。
115 このフィールドでは、呼び出したスレッドのリアルタイム優先度から
116 減算する値を指定する。この I/O リクエストの実行の優先度を
117 決定するために使用される (\fBpthread_setschedparam\fP(3) 参照)。
118 指定する値は 0 と \fIsysconf(_SC_AIO_PRIO_DELTA_MAX)\fP が返す値の間で
119 なければならない。このフィールドは、ファイル同期操作では無視される。
122 このフィールドは、非同期 I/O 操作が完了した際に呼び出し側に
123 どのように通知を行うかを指定する構造体である。
124 \fIaio_sigevent.sigev_notify\fP に指定できる値は、
125 \fBSIGEV_NONE\fP, \fBSIGEV_SIGNAL\fP, \fBSIGEV_THREAD\fP である。
126 詳細は \fBsigevent\fP(7) を参照。
130 \fBlio_listio\fP(3) でのみ使用される。
132 上記のリストにある標準の関数に加えて、GNU C ライブラリでは
133 以下に示す POSIX AIO API に対する拡張が提供されている。
136 glibc の POSIX AIO 実装の動作を調整するパラメータを設定する。
138 使用前に制御ブロックバッファを 0 で埋めるのはよい考えである
139 (\fBmemset\fP(3) 参照)。I/O 操作が実行中の間は、制御ブロックバッファと
140 \fIaio_buf\fP が指すバッファを変更してはならない。I/O 操作が完了するまで、
141 これらのバッファは有効な状態に保たなければならない。
143 同じ \fIaiocb\fP 構造体を使って、同時に複数の非同期の読み出し操作や
144 書き込み操作を行った場合に、どのような結果になるかは未定義である。
146 .\" http://lse.sourceforge.net/io/aio.html
147 .\" http://lse.sourceforge.net/io/aionotes.txt
148 .\" http://lwn.net/Articles/148755/
149 現在の Linux では、POSIX AIO 実装は glibc によりユーザ空間で提供
150 されている。このため、制限がいくつかあり、最も顕著なものは、I/O 操作を
151 実行する複数のスレッドの管理コストが高く、スケーラビリティに欠けること
152 である。しばらくの間、カーネルのステートマシンによる非同期 I/O の実装
153 の作業が行われているが (\fBio_submit\fP(2), \fBio_setup\fP(2),
154 \fBio_cancel\fP(2), \fBio_destroy\fP(2), \fBio_getevents\fP(2) 参照)、
155 この実装はまだ POSIX AIO 実装をカーネルシステムコールにより
160 \fIaiocb\fP 構造体の \fIaio_reqprio\fP フィールドが、0 より小さいか、
161 \fIsysconf(_SC_AIO_PRIO_DELTA_MAX)\fP が返す上限よりも大きかった。
163 POSIX AIO インターフェイスは glibc バージョン 2.1 以降で提供されている。
165 POSIX.1\-2001, POSIX.1\-2008.
167 下記のプログラムは、コマンドライン引き数で指定された名前のファイルを
168 それぞれオープンし、得られたファイルディスクリプタに対するリクエストを
169 \fBaio_read\fP(3) を使ってキューに入れる。その後、このプログラムはループに
170 入り、定期的に \fBaio_error\fP(3) を使ってまだ実行中の各 I/O 操作を監視す
171 る。各 I/O リクエストは、シグナルの配送による完了通知が行われるように設
172 定される。全ての I/O リクエストが完了した後、\fBaio_return\fP(3) を使って
175 \fBSIGQUIT\fP シグナル (control\-\e をタイプすると生成できる) を送ると、
176 このプログラムは \fBaio_cancel\fP(3) を使って
177 完了していない各リクエストにキャンセル要求を送る。
179 以下はこのプログラムを実行した際の出力例である。
180 この例では、標準入力に対して 2 つのリクエストを行い、
181 "abc" と "x" という 2 行の入力を行っている。
185 $ \fB./a.out /dev/stdin /dev/stdin\fP
186 opened /dev/stdin on descriptor 3
187 opened /dev/stdin on descriptor 4
189 for request 0 (descriptor 3): In progress
190 for request 1 (descriptor 4): In progress
192 I/O completion signal received
194 for request 0 (descriptor 3): I/O succeeded
195 for request 1 (descriptor 4): In progress
197 for request 1 (descriptor 4): In progress
199 I/O completion signal received
201 for request 1 (descriptor 4): I/O succeeded
202 All I/O requests completed
204 for request 0 (descriptor 3): 4
205 for request 1 (descriptor 4): 2
218 #define BUF_SIZE 20 /* Size of buffers for read operations */
220 #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
222 #define errMsg(msg) do { perror(msg); } while (0)
224 struct ioRequest { /* Application\-defined structure for tracking
228 struct aiocb *aiocbp;
231 static volatile sig_atomic_t gotSIGQUIT = 0;
232 /* On delivery of SIGQUIT, we attempt to
233 cancel all outstanding I/O requests */
235 static void /* Handler for SIGQUIT */
241 #define IO_SIGNAL SIGUSR1 /* Signal used to notify I/O completion */
243 static void /* Handler for I/O completion signal */
244 aioSigHandler(int sig, siginfo_t *si, void *ucontext)
246 write(STDOUT_FILENO, "I/O completion signal received\en", 31);
248 /* The corresponding ioRequest structure would be available as
249 struct ioRequest *ioReq = si\->si_value.sival_ptr;
250 and the file descriptor would then be available via
251 ioReq\->aiocbp\->aio_fildes */
255 main(int argc, char *argv[])
257 struct ioRequest *ioList;
258 struct aiocb *aiocbList;
261 int numReqs; /* Total number of queued I/O requests */
262 int openReqs; /* Number of I/O requests still in progress */
265 fprintf(stderr, "Usage: %s <pathname> <pathname>...\en",
272 /* Allocate our arrays */
274 ioList = calloc(numReqs, sizeof(struct ioRequest));
278 aiocbList = calloc(numReqs, sizeof(struct aiocb));
279 if (aiocbList == NULL)
282 /* Establish handlers for SIGQUIT and the I/O completion signal */
284 sa.sa_flags = SA_RESTART;
285 sigemptyset(&sa.sa_mask);
287 sa.sa_handler = quitHandler;
288 if (sigaction(SIGQUIT, &sa, NULL) == \-1)
289 errExit("sigaction");
291 sa.sa_flags = SA_RESTART | SA_SIGINFO;
292 sa.sa_sigaction = aioSigHandler;
293 if (sigaction(IO_SIGNAL, &sa, NULL) == \-1)
294 errExit("sigaction");
296 /* Open each file specified on the command line, and queue
297 a read request on the resulting file descriptor */
299 for (j = 0; j < numReqs; j++) {
300 ioList[j].reqNum = j;
301 ioList[j].status = EINPROGRESS;
302 ioList[j].aiocbp = &aiocbList[j];
304 ioList[j].aiocbp\->aio_fildes = open(argv[j + 1], O_RDONLY);
305 if (ioList[j].aiocbp\->aio_fildes == \-1)
307 printf("opened %s on descriptor %d\en", argv[j + 1],
308 ioList[j].aiocbp\->aio_fildes);
310 ioList[j].aiocbp\->aio_buf = malloc(BUF_SIZE);
311 if (ioList[j].aiocbp\->aio_buf == NULL)
314 ioList[j].aiocbp\->aio_nbytes = BUF_SIZE;
315 ioList[j].aiocbp\->aio_reqprio = 0;
316 ioList[j].aiocbp\->aio_offset = 0;
317 ioList[j].aiocbp\->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
318 ioList[j].aiocbp\->aio_sigevent.sigev_signo = IO_SIGNAL;
319 ioList[j].aiocbp\->aio_sigevent.sigev_value.sival_ptr =
322 s = aio_read(ioList[j].aiocbp);
329 /* Loop, monitoring status of I/O requests */
331 while (openReqs > 0) {
332 sleep(3); /* Delay between each monitoring step */
336 /* On receipt of SIGQUIT, attempt to cancel each of the
337 outstanding I/O requests, and display status returned
338 from the cancellation requests */
340 printf("got SIGQUIT; canceling I/O requests: \en");
342 for (j = 0; j < numReqs; j++) {
343 if (ioList[j].status == EINPROGRESS) {
344 printf(" Request %d on descriptor %d:", j,
345 ioList[j].aiocbp\->aio_fildes);
346 s = aio_cancel(ioList[j].aiocbp\->aio_fildes,
348 if (s == AIO_CANCELED)
349 printf("I/O canceled\en");
350 else if (s == AIO_NOTCANCELED)
351 printf("I/O not canceled\en");
352 else if (s == AIO_ALLDONE)
353 printf("I/O all done\en");
355 errMsg("aio_cancel");
362 /* Check the status of each I/O request that is still
365 printf("aio_error():\en");
366 for (j = 0; j < numReqs; j++) {
367 if (ioList[j].status == EINPROGRESS) {
368 printf(" for request %d (descriptor %d): ",
369 j, ioList[j].aiocbp\->aio_fildes);
370 ioList[j].status = aio_error(ioList[j].aiocbp);
372 switch (ioList[j].status) {
374 printf("I/O succeeded\en");
377 printf("In progress\en");
380 printf("Canceled\en");
387 if (ioList[j].status != EINPROGRESS)
393 printf("All I/O requests completed\en");
395 /* Check status return of all I/O requests */
397 printf("aio_return():\en");
398 for (j = 0; j < numReqs; j++) {
401 s = aio_return(ioList[j].aiocbp);
402 printf(" for request %d (descriptor %d): %ld\en",
403 j, ioList[j].aiocbp\->aio_fildes, (long) s);
411 \fBio_cancel\fP(2), \fBio_destroy\fP(2), \fBio_getevents\fP(2), \fBio_setup\fP(2),
412 \fBio_submit\fP(2), \fBaio_cancel\fP(3), \fBaio_error\fP(3), \fBaio_init\fP(3),
413 \fBaio_read\fP(3), \fBaio_return\fP(3), \fBaio_write\fP(3), \fBlio_listio\fP(3),
414 http://www.squid\-cache.org/~adrian/Reprint\-Pulavarty\-OLS2003.pdf
416 この man ページは Linux \fIman\-pages\fP プロジェクトのリリース 3.40 の一部
417 である。プロジェクトの説明とバグ報告に関する情報は
418 http://www.kernel.org/doc/man\-pages/ に書かれている。