このページの目次
epoll とイベント駆動
カバー範囲: epoll_create1/epoll_ctl/epoll_wait → LT vs ET → timerfd/signalfd/eventfd → select/pollとの比較 → epoll内部実装のポイント 対象: Linux 2.6+
概要
epoll は、Linux における高性能なイベント駆動プログラミングの標準インターフェースです。nginx、HAProxy、Redis はすべて epoll を基盤として構築されています。select/poll との根本的な違いは、epoll が O(1) の待機(アクティブな fd のみを返す)であるのに対し、select/poll は毎回 fd 集合全体を O(n) でスキャンする必要がある点です。
epoll API
int epfd = ; // epoll インスタンスの作成
struct epoll_event ev = ;
; // fd の登録
struct epoll_event events;
int nfds = ;
for
epoll_event.events
EPOLLIN: 読み込み可能 (データ到着または接続確立)
EPOLLOUT: 書き込み可能 (送信バッファに空きがある)
EPOLLERR: エラー (自動検出、設定不要)
EPOLLHUP: ハングアップ (相手が切断)
EPOLLRDHUP: 相手の書き込み側接続が閉じた (4.17+)
EPOLLET: エッジトリガー (以下参照)
EPOLLONESHOT: 一度限り (トリガー発生後に自動で削除され、EPOLL_CTL_MOD で再登録するまで有効にならない)
EPOLLEXCLUSIVE: 排他的ウェイクアップ (スラッシングを軽減、4.5+)
LT vs ET: 重要な違い
LT (Level-Triggered、デフォルト):
fd が読み込み可能/書き込み可能な状態である限り → 毎回の epoll_wait で返される
→ 単純: データの一部だけを読み取り、残りは次回に読むことができる
→ リスク: 読み込みが完了していない場合、次の epoll_wait でも返される → ループが必要
ET (Edge-Triggered):
状態遷移時のみ通知される (読み込み不可→読み込み可、書き込み不可→書き込み可)
→ 効率的: 重複通知がない
→ 要件: EAGAIN (すべて処理し終わった) になるまで読み書きを行う必要がある
→ O_NONBLOCK を必須とする (しないと read がブロックする可能性がある)
ET モードの正しい実装
// ET モードでは必ずループして読み込む必要がある:
while
timerfd / signalfd / eventfd: epoll の相棒
// 統一されたイベントループ: すべての非同期イベントを fd に変換し、epoll で一元管理する
int epfd = ;
// 1. ネットワークソケット
;
// 2. timerfd: タイマー
int tfd = ;
;
// 3. signalfd: シグナル
sigset_t mask; ; ;
;
int sfd = ;
;
// 4. eventfd: スレッド間通知
int efd = ;
;
// 単一スレッド: epoll_wait → すべてのイベントを統一して処理
while
select/poll との比較
| select | poll | epoll | |
|---|---|---|---|
| fd の数 | FD_SETSIZE (1024) | 上限なし | 上限なし |
| 待機 | O(n) スキャン | O(n) スキャン | O(1) アクティブ数 |
| 状態の保存 | 毎回渡す (スタック) | 毎回渡す (スタック) | カーネルが管理 (RB木) |
| エッジトリガー | なし | なし | あり (ET) |
| 1万コネクション (アイドル) | ~100μs | ~100μs | ~1μs |
epoll の内部実装
// fs/eventpoll.c
// epoll インスタンスは以下の要素を含む:
// 1. 赤黒木 (rbr): 登録された fd のリスト (epoll_ctl ADD → 挿入)
// 2. 準備済みリスト (rdllist): アクティブな fd (epoll_wait で返される)
//
// イベント到着 → ドライバ/プロトコルスタックが ep_poll_callback を呼び出す:
// → イベントが一致するか確認? → rdllist に追加
// → 待機者がいる場合 (epoll_wait) → ウェイクアップ
参考
- man: epoll(7), epoll_create1(2), epoll_ctl(2), epoll_wait(2)
- ソースコード:
fs/eventpoll.c - LWN: "The epoll API", "Edge triggered epoll"
キーワード: epoll, EPOLLET, EPOLLONESHOT, edge-triggered, timerfd, signalfd, eventfd, event loop