2 .\" Copyright (c) 2010 by Michael Kerrisk <mtk.manpages@gmail.com>
4 .\" %%%LICENSE_START(VERBATIM)
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.
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.
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
22 .\" Formatted or processed versions of this manual, if unaccompanied by
23 .\" the source, must acknowledge the copyright and authors of this work.
26 .\"*******************************************************************
28 .\" This file was generated with po4a. Translate the source file.
30 .\"*******************************************************************
31 .TH AIO 7 2012\-08\-05 Linux "Linux Programmer's Manual"
33 aio \- POSIX 非同期 I/O の概要
35 POSIX 非同期 (AIO) インターフェースを使うと、アプリケーションは、非同期
36 に (つまり、バックグラウンドで) 実行されるI/O 操作を一つ以上発行できる
37 ようになる。アプリケーションは I/O 操作の完了の通知方法を選択することが
38 できる。選択できる通知方法は、シグナルの配送、スレッドの起動、通知を行
41 POSIX AIO インターフェースは以下の関数で構成されている。
45 \fBread\fP(2) の非同期版である。
49 \fBwrite\fP(2) の非同期版である。
52 ファイルディスクリプタに対して行われた I/O 操作の
53 同期 (sync) リクエストをキューに入れる。
54 \fBfsync\fP(2) や \fBfdatasync\fP(2) の非同期版である。
57 キューに入れられた I/O リクエストのエラー状態を取得する。
60 完了した I/O リクエストの終了ステータスを取得する。
63 指定された I/O リクエストの集合 (要素は一つ以上) が完了するまで、
64 呼び出し側の実行を停止 (suspend) する。
68 完了していない I/O リクエストのキャンセルを試みる。
71 一回の関数呼び出しで複数の I/O リクエストをキューに入れる。
73 \fIaiocb\fP ("非同期 I/O 制御ブロック (asynchronous I/O control block)")
74 構造体は、I/O 操作を制御するパラメータを定義する。この型の引き数は上記
75 の全ての関数で使用されている。この構造体は以下の通りである。
82 /* The order of these fields is implementation\-dependent */
84 int aio_fildes; /* File descriptor */
85 off_t aio_offset; /* File offset */
86 volatile void *aio_buf; /* Location of buffer */
87 size_t aio_nbytes; /* Length of transfer */
88 int aio_reqprio; /* Request priority */
89 struct sigevent aio_sigevent; /* Notification method */
90 int aio_lio_opcode; /* Operation to be performed;
93 /* Various implementation\-internal fields not shown */
96 /* Operation codes for \(aqaio_lio_opcode\(aq: */
98 enum { LIO_READ, LIO_WRITE, LIO_NOP };
102 この構造体のフィールドは以下の通りである。
105 I/O 操作の実行対象となるファイルディスクリプタ。
108 I/O 操作を行うファイルオフセットを示す。
111 読み出し操作、書き込み操作でデータ転送に使用されるバッファ。
114 \fIaio_buf\fP が指すバッファのサイズ。
117 このフィールドでは、呼び出したスレッドのリアルタイム優先度から
118 減算する値を指定する。この I/O リクエストの実行の優先度を
119 決定するために使用される (\fBpthread_setschedparam\fP(3) 参照)。
120 指定する値は 0 と \fIsysconf(_SC_AIO_PRIO_DELTA_MAX)\fP が返す値の間で
121 なければならない。このフィールドは、ファイル同期操作では無視される。
124 このフィールドは、非同期 I/O 操作が完了した際に呼び出し側に
125 どのように通知を行うかを指定する構造体である。
126 \fIaio_sigevent.sigev_notify\fP に指定できる値は、
127 \fBSIGEV_NONE\fP, \fBSIGEV_SIGNAL\fP, \fBSIGEV_THREAD\fP である。
128 詳細は \fBsigevent\fP(7) を参照。
132 \fBlio_listio\fP(3) でのみ使用される。
134 上記のリストにある標準の関数に加えて、GNU C ライブラリでは
135 以下に示す POSIX AIO API に対する拡張が提供されている。
138 glibc の POSIX AIO 実装の動作を調整するパラメータを設定する。
142 \fIaiocb\fP 構造体の \fIaio_reqprio\fP フィールドが、0 より小さいか、
143 \fIsysconf(_SC_AIO_PRIO_DELTA_MAX)\fP が返す上限よりも大きかった。
145 POSIX AIO インターフェイスは glibc バージョン 2.1 以降で提供されている。
147 POSIX.1\-2001, POSIX.1\-2008.
149 使用前に制御ブロックバッファを 0 で埋めるのはよい考えである
150 (\fBmemset\fP(3) 参照)。I/O 操作が実行中の間は、制御ブロックバッファと
151 \fIaio_buf\fP が指すバッファを変更してはならない。I/O 操作が完了するまで、
152 これらのバッファは有効な状態に保たなければならない。
154 同じ \fIaiocb\fP 構造体を使って、同時に複数の非同期の読み出し操作や
155 書き込み操作を行った場合に、どのような結果になるかは未定義である。
157 .\" http://lse.sourceforge.net/io/aio.html
158 .\" http://lse.sourceforge.net/io/aionotes.txt
159 .\" http://lwn.net/Articles/148755/
160 現在の Linux では、POSIX AIO 実装は glibc によりユーザ空間で提供
161 されている。このため、制限がいくつかあり、最も顕著なものは、I/O 操作を
162 実行する複数のスレッドの管理コストが高く、スケーラビリティに欠けること
163 である。しばらくの間、カーネルのステートマシンによる非同期 I/O の実装
164 の作業が行われているが (\fBio_submit\fP(2), \fBio_setup\fP(2),
165 \fBio_cancel\fP(2), \fBio_destroy\fP(2), \fBio_getevents\fP(2) 参照)、
166 この実装はまだ POSIX AIO 実装をカーネルシステムコールにより
169 下記のプログラムは、コマンドライン引き数で指定された名前のファイルを
170 それぞれオープンし、得られたファイルディスクリプタに対するリクエストを
171 \fBaio_read\fP(3) を使ってキューに入れる。その後、このプログラムはループに
172 入り、定期的に \fBaio_error\fP(3) を使ってまだ実行中の各 I/O 操作を監視す
173 る。各 I/O リクエストは、シグナルの配送による完了通知が行われるように設
174 定される。全ての I/O リクエストが完了した後、\fBaio_return\fP(3) を使って
177 \fBSIGQUIT\fP シグナル (control\-\e をタイプすると生成できる) を送ると、
178 このプログラムは \fBaio_cancel\fP(3) を使って
179 完了していない各リクエストにキャンセル要求を送る。
181 以下はこのプログラムを実行した際の出力例である。
182 この例では、標準入力に対して 2 つのリクエストを行い、
183 "abc" と "x" という 2 行の入力を行っている。
187 $ \fB./a.out /dev/stdin /dev/stdin\fP
188 opened /dev/stdin on descriptor 3
189 opened /dev/stdin on descriptor 4
191 for request 0 (descriptor 3): In progress
192 for request 1 (descriptor 4): In progress
194 I/O completion signal received
196 for request 0 (descriptor 3): I/O succeeded
197 for request 1 (descriptor 4): In progress
199 for request 1 (descriptor 4): In progress
201 I/O completion signal received
203 for request 1 (descriptor 4): I/O succeeded
204 All I/O requests completed
206 for request 0 (descriptor 3): 4
207 for request 1 (descriptor 4): 2
220 #define BUF_SIZE 20 /* Size of buffers for read operations */
222 #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
224 #define errMsg(msg) do { perror(msg); } while (0)
226 struct ioRequest { /* Application\-defined structure for tracking
230 struct aiocb *aiocbp;
233 static volatile sig_atomic_t gotSIGQUIT = 0;
234 /* On delivery of SIGQUIT, we attempt to
235 cancel all outstanding I/O requests */
237 static void /* Handler for SIGQUIT */
243 #define IO_SIGNAL SIGUSR1 /* Signal used to notify I/O completion */
245 static void /* Handler for I/O completion signal */
246 aioSigHandler(int sig, siginfo_t *si, void *ucontext)
248 write(STDOUT_FILENO, "I/O completion signal received\en", 31);
250 /* The corresponding ioRequest structure would be available as
251 struct ioRequest *ioReq = si\->si_value.sival_ptr;
252 and the file descriptor would then be available via
253 ioReq\->aiocbp\->aio_fildes */
257 main(int argc, char *argv[])
259 struct ioRequest *ioList;
260 struct aiocb *aiocbList;
263 int numReqs; /* Total number of queued I/O requests */
264 int openReqs; /* Number of I/O requests still in progress */
267 fprintf(stderr, "Usage: %s <pathname> <pathname>...\en",
274 /* Allocate our arrays */
276 ioList = calloc(numReqs, sizeof(struct ioRequest));
280 aiocbList = calloc(numReqs, sizeof(struct aiocb));
281 if (aiocbList == NULL)
284 /* Establish handlers for SIGQUIT and the I/O completion signal */
286 sa.sa_flags = SA_RESTART;
287 sigemptyset(&sa.sa_mask);
289 sa.sa_handler = quitHandler;
290 if (sigaction(SIGQUIT, &sa, NULL) == \-1)
291 errExit("sigaction");
293 sa.sa_flags = SA_RESTART | SA_SIGINFO;
294 sa.sa_sigaction = aioSigHandler;
295 if (sigaction(IO_SIGNAL, &sa, NULL) == \-1)
296 errExit("sigaction");
298 /* Open each file specified on the command line, and queue
299 a read request on the resulting file descriptor */
301 for (j = 0; j < numReqs; j++) {
302 ioList[j].reqNum = j;
303 ioList[j].status = EINPROGRESS;
304 ioList[j].aiocbp = &aiocbList[j];
306 ioList[j].aiocbp\->aio_fildes = open(argv[j + 1], O_RDONLY);
307 if (ioList[j].aiocbp\->aio_fildes == \-1)
309 printf("opened %s on descriptor %d\en", argv[j + 1],
310 ioList[j].aiocbp\->aio_fildes);
312 ioList[j].aiocbp\->aio_buf = malloc(BUF_SIZE);
313 if (ioList[j].aiocbp\->aio_buf == NULL)
316 ioList[j].aiocbp\->aio_nbytes = BUF_SIZE;
317 ioList[j].aiocbp\->aio_reqprio = 0;
318 ioList[j].aiocbp\->aio_offset = 0;
319 ioList[j].aiocbp\->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
320 ioList[j].aiocbp\->aio_sigevent.sigev_signo = IO_SIGNAL;
321 ioList[j].aiocbp\->aio_sigevent.sigev_value.sival_ptr =
324 s = aio_read(ioList[j].aiocbp);
331 /* Loop, monitoring status of I/O requests */
333 while (openReqs > 0) {
334 sleep(3); /* Delay between each monitoring step */
338 /* On receipt of SIGQUIT, attempt to cancel each of the
339 outstanding I/O requests, and display status returned
340 from the cancellation requests */
342 printf("got SIGQUIT; canceling I/O requests: \en");
344 for (j = 0; j < numReqs; j++) {
345 if (ioList[j].status == EINPROGRESS) {
346 printf(" Request %d on descriptor %d:", j,
347 ioList[j].aiocbp\->aio_fildes);
348 s = aio_cancel(ioList[j].aiocbp\->aio_fildes,
350 if (s == AIO_CANCELED)
351 printf("I/O canceled\en");
352 else if (s == AIO_NOTCANCELED)
353 printf("I/O not canceled\en");
354 else if (s == AIO_ALLDONE)
355 printf("I/O all done\en");
357 errMsg("aio_cancel");
364 /* Check the status of each I/O request that is still
367 printf("aio_error():\en");
368 for (j = 0; j < numReqs; j++) {
369 if (ioList[j].status == EINPROGRESS) {
370 printf(" for request %d (descriptor %d): ",
371 j, ioList[j].aiocbp\->aio_fildes);
372 ioList[j].status = aio_error(ioList[j].aiocbp);
374 switch (ioList[j].status) {
376 printf("I/O succeeded\en");
379 printf("In progress\en");
382 printf("Canceled\en");
389 if (ioList[j].status != EINPROGRESS)
395 printf("All I/O requests completed\en");
397 /* Check status return of all I/O requests */
399 printf("aio_return():\en");
400 for (j = 0; j < numReqs; j++) {
403 s = aio_return(ioList[j].aiocbp);
404 printf(" for request %d (descriptor %d): %ld\en",
405 j, ioList[j].aiocbp\->aio_fildes, (long) s);
414 \fBio_cancel\fP(2), \fBio_destroy\fP(2), \fBio_getevents\fP(2), \fBio_setup\fP(2),
415 \fBio_submit\fP(2), \fBaio_cancel\fP(3), \fBaio_error\fP(3), \fBaio_init\fP(3),
416 \fBaio_read\fP(3), \fBaio_return\fP(3), \fBaio_write\fP(3), \fBlio_listio\fP(3)
418 .UR http://www.squid\-cache.org\:/~adrian\:/Reprint\-Pulavarty\-OLS2003.pdf
421 この man ページは Linux \fIman\-pages\fP プロジェクトのリリース 3.50 の一部
422 である。プロジェクトの説明とバグ報告に関する情報は
423 http://www.kernel.org/doc/man\-pages/ に書かれている。