I/Oの多重化(epoll API)を使いやすくしたい
はじめに epoll APIは有能だなあと思う今日この頃ですが、epoll_wait()してイベントを取り出す処理をべた書きするとコードが汚くなりがちです。少し前の記事ですが、epoll APIを使ったチャットサーバでは、epoll_wait()後のfor(){}が長くなり、読みにくいものになっていました。そこでイベント監視を少し一般化して裏でepollを呼ぶような仕組みを作りたくなりました。話がややこしいので結論だけ書いておくと、 epoll_data_t dataのユーザ定義のポインタに関数ポインタが混じった構造体を代入すると簡潔にアプリケーション側が書けそう インタレストリストへ追加/削除するような基本的な関数を作ってアプリケーション側から呼ぶと良さそう だねっていう話です。 後述するこれらの良くないであろう点でも書いていますが、あまりいいものではないです。 この記事内で使うコードの一式をGitHubに置いておきます。ヘッダファイルはこの記事内ですべてを載せてるわけではなので使ってみたい場合は以下のリポジトリからどうぞ。 いい感じにするための方針 方向性 いい感じにするには、struct epoll_eventのメンバであるepoll_data_t dataカギになりそうです。epoll_data_tは共用体なので実際に(同時に)使えるメンバは1つだけです。前回のチャットサーバと同様に、void *ptrを使うことを考えていきます。void *ですので任意の型で代入することができます。 typedef union epoll_data { void *ptr; // ユーザ定義のデータへのポインタ int fd; // ファイルディスクリプタ uint32_t u32; // 32ビット整数 uint64_t u64; // 64ビット整数 } epoll_data_t; 前回のチャットサーバで、for(){}が長くなっている原因はIO可能になって処理する内容を関数として作られていないからというのがありますが、何よりもそれらの処理が連結リストのポインタの操作が混じっていることが原因だと思います。そのため、ポインタ操作など面倒くさいものはできるだけ裏でやるようにすると良さそうです。 void*ptrに入れる構造体 void *ptrに代入するものを以下のstruct io_eventのようにしました。...