poll/epoll両用クラス

前のエントリで書いた内容、結局作った。
poll()とepoll()両用のC++インターフェース。うーむ使える。

select()を使うか、poll()を使うか、epoll()を使うか、kqueue()0を使うかという場面は、非常に(そうでもない?)多い。

OSで分けるのも面倒だし、それに全部実装するのか?という話になるので、結局select()でいいや、ってことになる。これは良くない。

というわけで、コレがあればそこのところ良きに計らってくれる。スバラシイ。


libeventなどと違って、関数をインライン化できるところがポイント。継承ではなくてtemplateで実装している。
コンパイラが賢ければ、オーバーヘッドはほぼゼロ。


イテレータ風インターフェースまで実装するのはやめたけど、ちゃんとC++っぽいところもポイント。


使い方的には↓こんな感じ。


#ifdef USE_EPOLL
typedef LinuxEpollMultiplexer Multiplexer;
#else
typedef PollMultiplexer Multiplexer;
#endif
// は "oneshot" オプション。
// 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も書き直しだな。