epoll 集合は epoll_create(2) で作成されるファイルディスクリプタに接続される。 ファイルディスクリプタに対する監視内容を epoll_ctl(2) で登録する。 最後に epoll_wait(2) で実際のイベント待ちを開始する。
rfd ファイルディスクリプタが EPOLLET フラグを使って epoll に追加されていると、 利用可能なデータがファイル入力バッファにまだ存在するにもかかわらず ステップ 5 の epoll_wait(2) の呼び出しでハングする可能性がある。 その一方で、リモートの接続先 (peer) は既に送られたデータに 基づいて応答を期待しているかもしれない。 このようなことが起こる理由は、エッジトリガイベント配送では、 モニタしているファイルでイベントが起ったときにのみイベントが 配送されるためである。 したがって、ステップ 5 では、呼び出し側は結果的に 入力バッファ内にすで存在するデータを待つことになるかもしれない。 上記の例では、 2 で行われた書き込みによって rfd に関するイベントが生成され、 3 でイベントが消費 (consume) される。 4 で行われる読み込み操作では、全部のバッファデータを消費しないので、 ステップ 5 で行われる epoll_wait(2) の呼び出しが 無期限に停止 (block) するかもしれない。
EPOLLET フラグ (エッジトリガ) を採用するアプリケーションでは、 インタフェースはブロックしない (non-blocking) ファイルディスクリプタを 使うべきである。 これは、ブロックされる読み込みや書き込みによって、 複数のファイルディスクリプタを扱うタスクが 停止してしまうのを避けるためである。 epoll をエッジトリガ (EPOLLET) インタフェースとして使うために提案される方法は以下の通りである。
一方、レベルトリガインタフェースとして使う場合は、 epoll は単に高速な poll(2) であり、使い方が同じなので、 poll(2) が使われているところではどこでも使用することができる。
エッジトリガを使った場合でも、複数のデータを受信すると複数の epoll イベントが生成されるので、 呼び出し側には EPOLLONESHOT フラグを指定するオプションがある。 このフラグは epoll に対して、 epoll_wait(2) によるイベントを受信した後で、関連するファイルディスクリプタを無効にさせる。 EPOLLONESHOT フラグが指定された場合、 epoll_ctl(2) に EPOLL_CTL_MOD を指定してファイルディスクリプタを再度使用できるようにするのは、 呼び出し側の責任である。
struct epoll_event ev, *events;
for (;;) {
nfds = epoll_wait(kdpfd, events, maxevents, -1);
for (n = 0; n < nfds; ++n) {
if (events[n].data.fd == listener) {
client = accept(listener, (struct sockaddr *) &local,
&addrlen);
if (client < 0){
perror("accept");
continue;
}
setnonblocking(client);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = client;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) {
fprintf(stderr, "epoll set insertion error: fd=%d\n",
client);
return -1;
}
} else {
do_use_fd(events[n].data.fd);
}
}
}
エッジトリガインタフェースとして使う場合、性能上の理由により、 一度 (EPOLLIN|EPOLLOUT) を指定してから (EPOLL_CTL_ADD で) ファイルディスクリプタを epoll インタフェースに追加することができる。 これにより、 epoll_ctl(2) に EPOLL_CTL_MOD を指定して呼び出すことで EPOLLIN と EPOLLOUT の連続的な切り替えが避けられる。
大きな I/O 空間がある場合、 その I/O 空間のデータを全て処理 (drain) しようとすると、 他のファイルが処理されず、飢餓を発生させることがある。 これは epoll に固有のものではない。
この問題の解決法は、準備済み状態のリストを管理して、 関連する data 構造体の中でファイルディスクリプタが 利用可能であるとマークすることである。 それによって、利用可能なすべてのファイルの中で どのファイルを処理する必要があるかを憶えることができ、 しかも順番に処理 (round robin) することができる。 既に利用可能であるファイルディスクリプタに対して それ以後に受け取るイベントを無視することもできる。
イベントキャッシュを使っている場合、 または epoll_wait(2) から返された全てのファイルディスクリプタを格納している場合、 クローズされたことを動的にマークする (つまり前のイベントの処理によってマークされる) 方法を提供すべきである。 epoll_wait(2) から 100 個のイベントを受け取り、 イベント #47 ではある条件でイベント #13 が閉じられると仮定する。 イベント #13 の構造体を削除しファイルディスクリプタを close(2) すると、イベントキャッシュはそのファイルディスクリプタを待つイベントが 存在するといって、混乱が起きる。
この問題を解決する 1 つの方法は、イベント 47 の処理をしている間に、 ファイルディスクリプタ 13 を削除して close(2) するために epoll_ctl(EPOLL_CTL_DEL) を呼び出し、関連付けられた data 構造体を削除済みとマークして、 クリーンアップリストにリンクすることである。 バッチ処理の中でファイルディスクリプタ 13 についての 他のイベントを見つけた場合、 そのファイルディスクリプタが以前に削除されたものであると分かるので、 混乱は起きない。