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

名前

       epoll - I/O イベント通知機能

書式

       #include <sys/epoll.h>

説明

       epoll  API は poll(2) と同様の処理を行う、つまり、複数のファイルディスクリプタを監視し、そ
       の中のいずれかが入出力可能な状態であるかを確認する。 epoll API  は、エッジトリガーインター
       フェースとレベルトリガーインターフェースのいずれとしても使用することができ、監視するファイ
       ルディスクリプターの数が多い場合にも使用できる。

       The central concept of the epoll API is the epoll instance, an  in-kernel  data  structure
       which, from a user-space perspective, can be considered as a container for two lists:

       • The  interest  list  (sometimes  also called the epoll set): the set of file descriptors
         that the process has registered an interest in monitoring.

       • The ready list: the set of file descriptors that are "ready" for I/O.  The ready list is
         a  subset  of  (or,  more precisely, a set of references to) the file descriptors in the
         interest list.  The ready list is dynamically populated by the kernel as a result of I/O
         activity on those file descriptors.

       The following system calls are provided to create and manage an epoll instance:

       • epoll_create(2) は新規の epoll インスタンスを作成し、そのインスタンスを参照する ファイル
         ディスクリプターを返す。(もっと新しい epoll_create1(2) では、 epoll_create(2) の機能が拡
         張されている)。

       • Interest  in particular file descriptors is then registered via epoll_ctl(2), which adds
         items to the interest list of the epoll instance.

       • epoll_wait(2)  waits for I/O events, blocking  the  calling  thread  if  no  events  are
         currently  available.   (This  system  call can be thought of as fetching items from the
         ready list of the epoll instance.)

   レベルトリガーとエッジトリガー
       epoll イベント配送 (distribution) インターフェースは、 エッジトリガー (ET)  としてもレベル
       トリガー  (LT) としても動作させることができる。 二つの配送機構の違いは、次のように説明でき
       る。 このようなシナリオが起こったとしよう:

       1. パイプの読み込み側を表すファイルディスクリプター (rfd)  が epoll インスタンスに登録され
          る。

       2. パイプへ書き込むプログラムが 2 kB のデータをパイプの書き込み側へ書き込む。

       3. epoll_wait(2)   を呼び出すと、読み込み可能 (ready) なファイルディスクリプターとして rfd
          が返る。

       4. パイプから読み出すプログラムが、1 kB のデータを rfd から読み出す。

       5. epoll_wait(2)  の呼び出しが行われる。

       rfd ファイルディスクリプターが EPOLLET フラグ (エッジトリガー) を使って epoll に追加されて
       いると、  利用可能なデータがファイル入力バッファーにまだ存在するにもかかわらず  ステップ 5epoll_wait(2) の呼び出しでハングする可能性がある。 その一方で、リモートの接続先  (peer)
       は既に送られたデータに 基づいて応答を期待しているかもしれない。 このようなことが起こる理由
       は、エッジトリガーイベント配送では、  モニタしているファイルでイベントが起ったときにのみイ
       ベントが 配送されるためである。 したがって、ステップ 5 では、呼び出し側は結果的に 入力バッ
       ファー内にすで存在するデータを待つことになるかもしれない。 上記の例では、 2 で行われた書き
       込みによって rfd に関するイベントが生成され、 3 でイベントが消費 (consume) される。 4 で行
       われる読み込み操作では、全部のバッファーデータを消費しないので、  ステップ  5   で行われる
       epoll_wait(2)  の呼び出しが 無期限に停止 (block) するかもしれない。

       EPOLLET       フラグを採用するアプリケーションでは、      インターフェースはブロックしない
       (nonblocking) ファイルディスクリプターを 使うべきである。 これは、ブロックされる読み込みや
       書き込みによって、 複数のファイルディスクリプターを扱うタスクが 停止してしまうのを避けるた
       めである。 epoll をエッジトリガー (EPOLLET)   インターフェースとして使うために提案される方
       法は以下の通りである。

       a) ブロックしないファイルディスクリプターと共に使う。

       b) read(2)  または write(2)  が EAGAIN を返した後でのみ、イベントを待つ。

       一方、レベルトリガーインターフェースとして使う場合
        (こちらがデフォルトである、  EPOLLET が指定されなかった場合)、 epoll は単に高速な poll(2)
       であり、使い方が同じなので、  poll(2)   が使われているところではどこでも使用することができ
       る。

       エッジトリガーを使った場合でも、複数のデータを受信すると複数の  epoll イベントが生成される
       ので、 呼び出し側には EPOLLONESHOT フラグを指定するオプションがある。  このフラグは  epoll
       に対して、  epoll_wait(2) によるイベントを受信した後で、関連するファイルディスクリプターを
       無効にさせる。 EPOLLONESHOT フラグが指定された場合、 epoll_ctl(2)  に EPOLL_CTL_MOD を指定
       してファイルディスクリプターを再度使用できるようにするのは、 呼び出し側の責任である。

       If  multiple  threads  (or  processes,  if  child  processes have inherited the epoll file
       descriptor across fork(2))  are blocked in epoll_wait(2) waiting on the  same  epoll  file
       descriptor  and  a  file descriptor in the interest list that is marked for edge-triggered
       (EPOLLET)  notification becomes ready, just one of the threads (or  processes)  is  awoken
       from  epoll_wait(2).   This  provides a useful optimization for avoiding "thundering herd"
       wake-ups in some scenarios.

   autosleep との関係
       システムが /sys/power/autosleep 経由で autosleep モードになっていて、 デバイスをスリープ状
       態から起こすイベントが発生した場合、  デバイスドライバーはデバイスを起こしておくのはそのイ
       ベントがキューに入るまでだけである。  イベントが処理されるまでデバイスを起こしたままにして
       おくには、 epoll_ctl(2) EPOLLWAKEUP フラグを使う必要がある。

       EPOLLWAKEUP  フラグが struct epoll_eventevents フィールドでセットされた場合、 イベント
       がキューに入った瞬間から、epoll_wait(2) がそのイベントを返し次の epoll_wait(2)  の呼び出し
       が行われるまでの間、システムは起きたままの状態になる。  イベントが上記の時間の範囲を超えて
       システムを起きたままの状態にしておく必要がある場合は、 2 番目の epoll_wait(2) の呼び出しの
       前に別の wake_lock を取る必要がある。

   /proc インターフェース
       epoll  が消費するカーネルメモリーの量を制限するために、 以下のインターフェースを使用するこ
       とができる。

       /proc/sys/fs/epoll/max_user_watches (Linux 2.6.28 以降)
              このファイルは、あるユーザーがシステム上の全ての  epoll  インスタンスに  登録できる
              ファイルディスクリプターの総数の上限を規定する。  この上限は実ユーザー  ID 単位であ
              る。 登録されたファイルディスクリプター 1 つが消費するメモリー量は、 32  ビットカー
              ネルでおよそ  90  バイト、  64 ビットカーネルでおよそ 160 バイトである。 現在のとこ
              ろ、 max_user_watches のデフォルト値は、利用可能なメモリー下限の 1/25 (4%) であり、
              登録で消費されるメモリー量 (バイト単位) で割った値となる。

   おすすめな使用例
       レベルトリガーインターフェースとして使用するときの  epoll  の使い方は  poll(2)  と同じであ
       る。   しかしエッジトリガーとして使う場合は、   アプリケーションのイベントループでストール
       (stall) しないように、 使い方をより明確にしておく必要がある。 この例では、リスナはブロック
       しないソケットであり、 listen(2)  が呼ばれている。 関数 do_use_fd() は、  read(2)   または
       write(2)   によって  EAGAIN が返されるまでは、新しい準備済みのファイルディスクリプターを使
       う。 イベント駆動ステートマシンアプリケーションは、 EAGAIN  を受信した後、カレントの状態を
       記録しておくべきである。 これにより、次の do_use_fd() 呼び出しのときに、以前に停止したとこ
       ろから read(2)  または write(2)  を継続することができる。

           #define MAX_EVENTS 10
           struct epoll_event ev, events[MAX_EVENTS];
           int listen_sock, conn_sock, nfds, epollfd;

           /* Code to set up listening socket, 'listen_sock',
              (socket(), bind(), listen()) omitted */

           epollfd = epoll_create1(0);
           if (epollfd == -1) {
               perror("epoll_create1");
               exit(EXIT_FAILURE);
           }

           ev.events = EPOLLIN;
           ev.data.fd = listen_sock;
           if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
               perror("epoll_ctl: listen_sock");
               exit(EXIT_FAILURE);
           }

           for (;;) {
               nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
               if (nfds == -1) {
                   perror("epoll_wait");
                   exit(EXIT_FAILURE);
               }

               for (n = 0; n < nfds; ++n) {
                   if (events[n].data.fd == listen_sock) {
                       conn_sock = accept(listen_sock,
                                          (struct sockaddr *) &addr, &addrlen);
                       if (conn_sock == -1) {
                           perror("accept");
                           exit(EXIT_FAILURE);
                       }
                       setnonblocking(conn_sock);
                       ev.events = EPOLLIN | EPOLLET;
                       ev.data.fd = conn_sock;
                       if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
                                   &ev) == -1) {
                           perror("epoll_ctl: conn_sock");
                           exit(EXIT_FAILURE);
                       }
                   } else {
                       do_use_fd(events[n].data.fd);
                   }
               }
           }

       エッジトリガーインターフェースとして使う場合、性能上の理由により、 一度 (EPOLLIN|EPOLLOUT)
       を指定してから  (EPOLL_CTL_ADD で) ファイルディスクリプターを epoll インターフェースに追加
       することができる。 これにより、 epoll_ctl(2)   に  EPOLL_CTL_MOD  を指定して呼び出すことで
       EPOLLINEPOLLOUT の連続的な切り替えが避けられる。

   質問と解答
       0.  What  is  the  key  used to distinguish the file descriptors registered in an interest
           list?

           キーはファイルディスクリプター番号とオープンファイル記述 (open file description)  の組
           である  (オープンファイル記述は "open file handle" とも 呼ばれ、オープンされたファイル
           のカーネルの内部表現である)。

       1.  1 つの epoll インスタンスに同じファイルディスクリプターを 2 回登録するとどうなるか?

           たぶん EEXIST を受け取るだろう。 しかしながら、同じ epoll インスタンスに対して複製され
           たファイルディスクリプターを追加することは可能である    (dup(2),   dup2(2),   fcntl(2)
           F_DUPFD など)。 複製したファイルディスクリプターを異なる events マスクで登録すれば、イ
           ベントをフィルタリングするのに この機能は有用な手法である。

       2.  2 つの epoll インスタンスが同じファイルディスクリプターを待ち受けることは可能か? もし
           可能であれば、イベントは両方の epoll ファイルディスクリプターに報告されるか?

           イベントは両方に報告される。  しかしながら、これを正しく扱うには注意深くプログラミング
           する必要が あるかもしれない。

       3.  epoll ファイルディスクリプター自身は poll/epoll/select が可能か?

           可能である。 epoll ファイルディスクリプターに処理待ちのイベントがある場合は、 読み出し
           可能だと通知されることだろう。

       4.  epoll ファイルディスクリプターを自身のファイルディスクリプター集合に  入れようとすると
           どうなるか?

           epoll_ctl(2)   の呼び出しは  (EINVAL  で) 失敗する。 ただし epoll ファイルディスクリプ
           ターを他の epoll ファイルディスクリプター集合の内部に追加することは可能である。

       5.  epoll ファイルディスクリプターを  UNIX  ドメインソケットで他のプロセスに送ることは可能
           か?

           Yes, but it does not make sense to do this, since the receiving process would not have
           copies of the file descriptors in the interest list.

       6.  Will closing a file descriptor cause it to be removed from all epoll interest lists?

           Yes, but be aware of the following point.  A file descriptor is a reference to an open
           file  description (see open(2)).  Whenever a file descriptor is duplicated via dup(2),
           dup2(2), fcntl(2)  F_DUPFD, or fork(2), a new file descriptor referring  to  the  same
           open  file  description is created.  An open file description continues to exist until
           all file descriptors referring to it have been closed.

           A file descriptor is removed from an interest list only after all the file descriptors
           referring  to  the underlying open file description have been closed.  This means that
           even after a file descriptor that is part of an interest list has been closed,  events
           may  be  reported  for that file descriptor if other file descriptors referring to the
           same underlying file description remain open.  To prevent  this  happening,  the  file
           descriptor  must  be  explicitly  removed  from  the interest list (using epoll_ctl(2)
           EPOLL_CTL_DEL)  before it is duplicated.  Alternatively, the application  must  ensure
           that  all file descriptors are closed (which may be difficult if file descriptors were
           duplicated behind the scenes by library functions that used dup(2)  or fork(2)).

       7.  2 つ以上のイベントが epoll_wait(2)  コールの間に発生した場合、それらはまとめて報告され
           るか、 それとも別々に報告されるか?

           まとめて報告されるだろう。

       8.  ファイルディスクリプターに対する操作は、  既に集められているがまだ報告されていないイベ
           ントに影響するか?

           既存のファイルディスクリプターに対して 2 つの操作を行うことができる。 この場合、削除に
           は意味がない。 変更すると、使用可能な I/O が再び読み込まれる。

       9.  EPOLLET  フラグ (エッジトリガー動作) を使っている場合、 EAGAIN を受け取るまで、 継続し
           てファイルディスクリプターを読み書きする必要があるか?

           epoll_wait(2)  からイベントを受け取ることは、 そのファイルディスクリプターが要求された
           I/O 操作に対して準備済みである、 ということをユーザーに示すものである。 次の (ブロック
           しない) read/write で EAGAIN  を受け取るまではファイルディスクリプターは準備済みである
           と  考えなければならない。 そのファイルディスクリプターをいつどのように使うかは、 全く
           ユーザーに任されてる。

           パケット指向やトークン指向のファイル (例えば、データグラムソケット、 canonical  モード
           の端末)  では、  読み込み用 / 書き込み用の I/O 空間の末尾を検知する唯一の方法は EAGAIN
           になるまで read/write を行うことである。

           ストリーム指向のファイル (例えば、パイプ、FIFO、ストリームソケット) では、  読み込み用
           / 書き込み用の I/O 空間が使い尽くされた状態は、 対象となるファイルディスクリプターから
           読み込んだデータ量または   書き込んだデータ量をチェックすることでも検知できる。   例え
           ば、ある特定の量のデータを読み込むために  read(2)  を呼んだときに、 read(2) が返したバ
           イト数がそれより少なかった場合、 そのファイルディスクリプターの読み込み用  I/O  空間が
           使い尽くされたことが分かる。  write(2)  を使って書き込みをするときも、同じことが言える
           (監視しているファイルディスクリプターが常にストリーム指向のファイルを 参照していること
           を保証できない場合には、後者の手法の使用を避けること)。

   ありがちな落とし穴と回避方法
       o 飢餓 (starvation) (エッジトリガー)

       大きな  I/O 空間がある場合、 その I/O 空間のデータを全て処理 (drain) しようとすると、 他の
       ファイルが処理されず、飢餓を発生させることがある (この問題は epoll に固有のものではない)。

       この問題の解決法は、準備済み状態のリストを管理して、  関連する  data  構造体の中でファイル
       ディスクリプターが 利用可能であるとマークすることである。 それによって、利用可能なすべての
       ファイルの中で   どのファイルを処理する必要があるかを憶えることができ、   しかも順番に処理
       (round robin) することができる。 既に利用可能であるファイルディスクリプターに対して それ以
       後に受け取るイベントを無視することもできる。

       o イベントキャッシュを使っている場合

       イベントキャッシュを使っている場合、 または epoll_wait(2)   から返された全てのファイルディ
       スクリプターを格納している場合、  クローズされたことを動的にマークする (つまり前のイベント
       の処理によってマークされる) 方法を提供すべきである。 epoll_wait(2) から 100 個のイベントを
       受け取り、  イベント  #47 ではある条件でイベント #13 が閉じられると仮定する。 イベント #13
       の構造体を削除しファイルディスクリプターを close(2)   すると、イベントキャッシュはそのファ
       イルディスクリプターを待つイベントが 存在するといって、混乱が起きる。

       この問題を解決する  1  つの方法は、イベント 47 の処理をしている間に、 ファイルディスクリプ
       ター 13 を削除して close(2) するために epoll_ctl(EPOLL_CTL_DEL)   を呼び出し、関連付けられ
       た data 構造体を削除済みとマークして、 クリーンアップリストにリンクすることである。 バッチ
       処理の中でファイルディスクリプター 13 についての 他のイベントを見つけた場合、 そのファイル
       ディスクリプターが以前に削除されたものであると分かるので、 混乱は起きない。

バージョン

       epoll  API は Linux カーネル 2.5.44 に導入された。 glibc でのサポートはバージョン 2.3.2 で
       追加された。

準拠

       epoll API は Linux 固有である。 他のシステムでも同様の機構が提供されている場合がある。  例
       えば、FreeBSD の kqueue や Solaris の /dev/poll などである。

注意

       The  set  of  file descriptors that is being monitored via an epoll file descriptor can be
       viewed via the entry for the epoll file descriptor  in  the  process's  /proc/[pid]/fdinfo
       directory.  See proc(5)  for further details.

       The  kcmp(2)   KCMP_EPOLL_TFD  operation  can be used to test whether a file descriptor is
       present in an epoll instance.

関連項目

       epoll_create(2), epoll_create1(2), epoll_ctl(2), epoll_wait(2), poll(2), select(2)

この文書について

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