Provided by: manpages-ja_0.5.0.0.20221215+dfsg-1_all
名前
aio - POSIX 非同期 I/O の概要
説明
POSIX 非同期 (AIO) インターフェースを使うと、アプリケーションは、非同期 に (つまり、バック グラウンドで) 実行されるI/O 操作を一つ以上発行できる ようになる。アプリケーションは I/O 操 作の完了の通知方法を選択することが できる。選択できる通知方法は、シグナルの配送、スレッド の起動、通知を行 わないである。 POSIX AIO インターフェースは以下の関数で構成されている。 aio_read(3) 読み出しリクエストをキューに入れる。 read(2) の非同期版である。 aio_write(3) 書き込みリクエストをキューに入れる。 write(2) の非同期版である。 aio_fsync(3) ファイルディスクリプターに対して行われた I/O 操作の 同期 (sync) リクエストをキュー に入れる。 fsync(2) や fdatasync(2) の非同期版である。 aio_error(3) キューに入れられた I/O リクエストのエラー状態を取得する。 aio_return(3) 完了した I/O リクエストの終了ステータスを取得する。 aio_suspend(3) 指定された I/O リクエストの集合 (要素は一つ以上) が完了するまで、 呼び出し側の実行 を停止 (suspend) する。 aio_cancel(3) 指定されたファイルディスクリプターに関する 完了していない I/O リクエストのキャンセ ルを試みる。 lio_listio(3) 一回の関数呼び出しで複数の I/O リクエストをキューに入れる。 aiocb ("非同期 I/O 制御ブロック (asynchronous I/O control block)") 構造体は、I/O 操作を制 御するパラメーターを定義する。この型の引数は上記 の全ての関数で使用されている。この構造体 は以下の通りである。 #include <aiocb.h> struct aiocb { /* The order of these fields is implementation-dependent */ int aio_fildes; /* File descriptor */ off_t aio_offset; /* File offset */ volatile void *aio_buf; /* Location of buffer */ size_t aio_nbytes; /* Length of transfer */ int aio_reqprio; /* Request priority */ struct sigevent aio_sigevent; /* Notification method */ int aio_lio_opcode; /* Operation to be performed; lio_listio() only */ /* Various implementation-internal fields not shown */ }; /* Operation codes for 'aio_lio_opcode': */ enum { LIO_READ, LIO_WRITE, LIO_NOP }; この構造体のフィールドは以下の通りである。 aio_fildes I/O 操作の実行対象となるファイルディスクリプター。 aio_offset I/O 操作を行うファイルオフセットを示す。 aio_buf 読み出し操作、書き込み操作でデータ転送に使用されるバッファー。 aio_nbytes aio_buf が指すバッファーのサイズ。 aio_reqprio このフィールドでは、呼び出したスレッドのリアルタイム優先度から 減算する値を指定す る。この I/O リクエストの実行の優先度を 決定するために使用される (pthread_setschedparam(3) 参照)。 指定する値は 0 と sysconf(_SC_AIO_PRIO_DELTA_MAX) が返す値の間で なければならない。このフィールドは、ファイル同期操作では無視される。 aio_sigevent このフィールドは、非同期 I/O 操作が完了した際に呼び出し側に どのように通知を行うか を指定する構造体である。 aio_sigevent.sigev_notify に指定できる値は、 SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD である。 詳細は sigevent(7) を参照。 aio_lio_opcode 実行される操作の種別。 lio_listio(3) でのみ使用される。 上記のリストにある標準の関数に加えて、GNU C ライブラリでは 以下に示す POSIX AIO API に対す る拡張が提供されている。 aio_init(3) glibc の POSIX AIO 実装の動作を調整するパラメーターを設定する。
エラー
EINVAL aiocb 構造体の aio_reqprio フィールドが、0 より小さいか、 sysconf(_SC_AIO_PRIO_DELTA_MAX) が返す上限よりも大きかった。
バージョン
POSIX AIO インターフェイスは glibc バージョン 2.1 以降で提供されている。
準拠
POSIX.1-2001, POSIX.1-2008.
注意
使用前に制御ブロックバッファーを 0 で埋めるのはよい考えである (memset(3) 参照)。I/O 操作が 実行中の間は、制御ブロックバッファーと aio_buf が指すバッファーを変更してはならない。I/O 操作が完了するまで、 これらのバッファーは有効な状態に保たなければならない。 同じ aiocb 構造体を使って、同時に複数の非同期の読み出し操作や 書き込み操作を行った場合 に、どのような結果になるかは未定義である。 現在の Linux では、POSIX AIO 実装は glibc によりユーザー空間で提供 されている。このた め、制限がいくつかあり、最も顕著なものは、I/O 操作を 実行する複数のスレッドの管理コストが 高く、スケーラビリティに欠けること である。しばらくの間、カーネルのステートマシンによる非 同期 I/O の実装 の作業が行われているが (io_submit(2), io_setup(2), io_cancel(2), io_destroy(2), io_getevents(2) 参照)、 この実装はまだ POSIX AIO 実装をカーネルシステムコー ルにより 再実装するほど成熟したものてはない。
例
下記のプログラムは、コマンドライン引数で指定された名前のファイルを それぞれオープンし、得 られたファイルディスクリプターに対するリクエストを aio_read(3) を使ってキューに入れる。そ の後、このプログラムはループに 入り、定期的に aio_error(3) を使ってまだ実行中の各 I/O 操作 を監視す る。各 I/O リクエストは、シグナルの配送による完了通知が行われるように設 定され る。全ての I/O リクエストが完了した後、aio_return(3) を使って それぞれのステータスを取得す る。 SIGQUIT シグナル (control-\ をタイプすると生成できる) を送ると、 このプログラムは aio_cancel(3) を使って 完了していない各リクエストにキャンセル要求を送る。 以下はこのプログラムを実行した際の出力例である。 この例では、標準入力に対して 2 つのリクエ ストを行い、 "abc" と "x" という 2 行の入力を行っている。 $ ./a.out /dev/stdin /dev/stdin opened /dev/stdin on descriptor 3 opened /dev/stdin on descriptor 4 aio_error(): for request 0 (descriptor 3): In progress for request 1 (descriptor 4): In progress abc I/O completion signal received aio_error(): for request 0 (descriptor 3): I/O succeeded for request 1 (descriptor 4): In progress aio_error(): for request 1 (descriptor 4): In progress x I/O completion signal received aio_error(): for request 1 (descriptor 4): I/O succeeded All I/O requests completed aio_return(): for request 0 (descriptor 3): 4 for request 1 (descriptor 4): 2 プログラムのソース #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <errno.h> #include <aio.h> #include <signal.h> #define BUF_SIZE 20 /* Size of buffers for read operations */ #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) struct ioRequest { /* Application-defined structure for tracking I/O requests */ int reqNum; int status; struct aiocb *aiocbp; }; static volatile sig_atomic_t gotSIGQUIT = 0; /* On delivery of SIGQUIT, we attempt to cancel all outstanding I/O requests */ static void /* Handler for SIGQUIT */ quitHandler(int sig) { gotSIGQUIT = 1; } #define IO_SIGNAL SIGUSR1 /* Signal used to notify I/O completion */ static void /* Handler for I/O completion signal */ aioSigHandler(int sig, siginfo_t *si, void *ucontext) { if (si->si_code == SI_ASYNCIO) { write(STDOUT_FILENO, "I/O completion signal received\n", 31); /* The corresponding ioRequest structure would be available as struct ioRequest *ioReq = si->si_value.sival_ptr; and the file descriptor would then be available via ioReq->aiocbp->aio_fildes */ } } int main(int argc, char *argv[]) { struct sigaction sa; int s; int numReqs; /* Total number of queued I/O requests */ int openReqs; /* Number of I/O requests still in progress */ if (argc < 2) { fprintf(stderr, "Usage: %s <pathname> <pathname>...\n", argv[0]); exit(EXIT_FAILURE); } numReqs = argc - 1; /* Allocate our arrays */ struct ioRequest *ioList = calloc(numReqs, sizeof(*ioList)); if (ioList == NULL) errExit("calloc"); struct aiocb *aiocbList = calloc(numReqs, sizeof(*aiocbList)); if (aiocbList == NULL) errExit("calloc"); /* Establish handlers for SIGQUIT and the I/O completion signal */ sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sa.sa_handler = quitHandler; if (sigaction(SIGQUIT, &sa, NULL) == -1) errExit("sigaction"); sa.sa_flags = SA_RESTART | SA_SIGINFO; sa.sa_sigaction = aioSigHandler; if (sigaction(IO_SIGNAL, &sa, NULL) == -1) errExit("sigaction"); /* Open each file specified on the command line, and queue a read request on the resulting file descriptor */ for (int j = 0; j < numReqs; j++) { ioList[j].reqNum = j; ioList[j].status = EINPROGRESS; ioList[j].aiocbp = &aiocbList[j]; ioList[j].aiocbp->aio_fildes = open(argv[j + 1], O_RDONLY); if (ioList[j].aiocbp->aio_fildes == -1) errExit("open"); printf("opened %s on descriptor %d\n", argv[j + 1], ioList[j].aiocbp->aio_fildes); ioList[j].aiocbp->aio_buf = malloc(BUF_SIZE); if (ioList[j].aiocbp->aio_buf == NULL) errExit("malloc"); ioList[j].aiocbp->aio_nbytes = BUF_SIZE; ioList[j].aiocbp->aio_reqprio = 0; ioList[j].aiocbp->aio_offset = 0; ioList[j].aiocbp->aio_sigevent.sigev_notify = SIGEV_SIGNAL; ioList[j].aiocbp->aio_sigevent.sigev_signo = IO_SIGNAL; ioList[j].aiocbp->aio_sigevent.sigev_value.sival_ptr = &ioList[j]; s = aio_read(ioList[j].aiocbp); if (s == -1) errExit("aio_read"); } openReqs = numReqs; /* Loop, monitoring status of I/O requests */ while (openReqs > 0) { sleep(3); /* Delay between each monitoring step */ if (gotSIGQUIT) { /* On receipt of SIGQUIT, attempt to cancel each of the outstanding I/O requests, and display status returned from the cancellation requests */ printf("got SIGQUIT; canceling I/O requests: \n"); for (int j = 0; j < numReqs; j++) { if (ioList[j].status == EINPROGRESS) { printf(" Request %d on descriptor %d:", j, ioList[j].aiocbp->aio_fildes); s = aio_cancel(ioList[j].aiocbp->aio_fildes, ioList[j].aiocbp); if (s == AIO_CANCELED) printf("I/O canceled\n"); else if (s == AIO_NOTCANCELED) printf("I/O not canceled\n"); else if (s == AIO_ALLDONE) printf("I/O all done\n"); else perror("aio_cancel"); } } gotSIGQUIT = 0; } /* Check the status of each I/O request that is still in progress */ printf("aio_error():\n"); for (int j = 0; j < numReqs; j++) { if (ioList[j].status == EINPROGRESS) { printf(" for request %d (descriptor %d): ", j, ioList[j].aiocbp->aio_fildes); ioList[j].status = aio_error(ioList[j].aiocbp); switch (ioList[j].status) { case 0: printf("I/O succeeded\n"); break; case EINPROGRESS: printf("In progress\n"); break; case ECANCELED: printf("Canceled\n"); break; default: perror("aio_error"); break; } if (ioList[j].status != EINPROGRESS) openReqs--; } } } printf("All I/O requests completed\n"); /* Check status return of all I/O requests */ printf("aio_return():\n"); for (int j = 0; j < numReqs; j++) { ssize_t s; s = aio_return(ioList[j].aiocbp); printf(" for request %d (descriptor %d): %zd\n", j, ioList[j].aiocbp->aio_fildes, s); } exit(EXIT_SUCCESS); }
関連項目
io_cancel(2), io_destroy(2), io_getevents(2), io_setup(2), io_submit(2), aio_cancel(3), aio_error(3), aio_init(3), aio_read(3), aio_return(3), aio_write(3), lio_listio(3) "Asynchronous I/O Support in Linux 2.5", Bhattacharya, Pratt, Pulavarty, and Morgan, Proceedings of the Linux Symposium, 2003, ⟨https://www.kernel.org/doc/ols/2003/ols2003-pages-351-366.pdf⟩
この文書について
この man ページは Linux man-pages プロジェクトのリリース 5.10 の一部である。プロジェクトの 説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。