poll/epoll両用クラス
前のエントリで書いた内容、結局作った。
poll()とepoll()両用のC++インターフェース。うーむ使える。
select()を使うか、poll()を使うか、epoll()を使うか、kqueue()0を使うかという場面は、非常に(そうでもない?)多い。
OSで分けるのも面倒だし、それに全部実装するのか?という話になるので、結局select()でいいや、ってことになる。これは良くない。
というわけで、コレがあればそこのところ良きに計らってくれる。スバラシイ。
libeventなどと違って、関数をインライン化できるところがポイント。継承ではなくてtemplateで実装している。
コンパイラが賢ければ、オーバーヘッドはほぼゼロ。
イテレータ風インターフェースまで実装するのはやめたけど、ちゃんとC++っぽいところもポイント。
使い方的には↓こんな感じ。
#ifdef USE_EPOLL
typedef LinuxEpollMultiplexer
#else
typedef PollMultiplexer
#endif
//
// 1回イベントが届くと、そのファイルディスクリプタが
// 監視対象から外される。もう一度監視対象に戻すには
// reactivate()を呼ぶ
Multiplexer mp; // 場合によっては例外を投げるので注意
int listen_sockをsocketしてbindしてlistenして ...
mp.add(listen_socket, Multiplexer::EVENT_IN);
// accept()できるようになったら知らされる
while(1) {
Multiplexer::events_type events( mp.wait() );
// wait()はタイムアウト時間も指定可能
// 省略するとタイムアウトしない
try {
for( Multiplexer::events_type::ev_t ev(events.next());
ev.fd != -1;
ev = events.next() ) {
if( ev.fd == listen_sock ) {
int sock = accept(ev.fd);
mp.add(sock, Multiplexer::EVENT_IN);
} else {
// たぶんev.fdにデータが届いてます
hoge(ev.fd);
}
// oneshotオプションがtrueなので、
// 1回イベントが届いたらreactivateが必要
// reactivateはスレッドセーフ!
// 別のスレッドからreactivateしてもOK
mp.reactivate(ev, Multiplexer::EVENT_IN);
}
} catch ( ... ) {
// エラーですよ
}
}
スバラシイ。前代未聞の簡潔さ。
V-FIELDは、このあたりの処理に字面200行くらいある。しかもselet()。スレッドセーフで例外安全にしようと思ったら、やたら膨らんでしまった。
今度V-FIELDも書き直しだな。