Provided by: manpages-ja_0.5.0.0.20210215+dfsg-1_all bug

名前

       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_filedes     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 <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)

       #define errMsg(msg)  do { perror(msg); } 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)
       {
           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 ioRequest *ioList;
           struct aiocb *aiocbList;
           struct sigaction sa;
           int s, j;
           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 */

           ioList = calloc(numReqs, sizeof(struct ioRequest));
           if (ioList == NULL)
               errExit("calloc");

           aiocbList = calloc(numReqs, sizeof(struct aiocb));
           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 (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 (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
                               errMsg("aio_cancel");
                       }
                   }

                   gotSIGQUIT = 0;
               }

               /* Check the status of each I/O request that is still
                  in progress */

               printf("aio_error():\n");
               for (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:
                           errMsg("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 (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)

       ⟨http://www.squid-cache.org/~adrian/Reprint-Pulavarty-OLS2003.pdf

この文書について

       この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部 である。プロジェクト
       の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。