vcacheは、仮想アドレスと物理ページの対応付けの変更をコールバック関数によって通知する仕組みである。
後述するfutexの実装に使用されるため、カーネル2.6に追加された。
futexは、伝統的なUNIXカーネルで使われているsleep/wakeupとよく似た同期機構をユーザーランドに対して提供する。
主にNPTL(Native POSIX Thread Library)などのライブラリの実装に使われるため、アプリケーションから直接利用することはあまりないと思われるが、POSIX ThreadはJavaスレッドの実装などにも用いられており、同期処理を多用するアプリケーションには利益があるだろう。
futexシステムコールの主な機能はFUTEX_WAITとFUTEX_WAKEである。
futexシステムコールは、共有メモリ中のアドレスをウェイトポイントとして使用する。しかし、共有メモリがマップされているアドレスはプロセスごとに違うため、仮想アドレスをそのまま使うことはできない。そこで、カーネル内で物理アドレスに変換してから使用するのだが、ここで注意しなければならないのは、対応する物理アドレスはページアウト/ページインなどで容易に変わってしまうことだ。カーネル2.6は、前述のvcacheを利用することでこれを解決している。
参考までに、NPTLのpthread mutexの実装を簡単に書くと次のようになっている。
以上のように、競合がない場合はユーザー空間で処理が完結するため、システムコールのオーバーヘッドは実際にスレッド間の競合が発生した場合に限られている。
NFSサーバがREADリクエストを処理する際、カーネル2.4はページキャッシュからNFS送信用バッファへいったんメモリコピーを行う。それをプロトコル層でさらにソケットバッファにコピーし、そのうえでネットワークドライバが送信処理を行っていた。
カーネル2.6では、ページキャッシュに使われているページを直接プロトコル層に渡し、可能であればそのままネットワークドライバまで渡すように改良された。これにより、無駄なコピー処理のオーバーヘッドが削減されるのはもちろん、プロセッサ内部のキャッシュメモリからほかの有用なデータが追い出されることが減ると期待できる。
select/pollのインターフェイスは、大規模なWebサーバなど、多くのディスクリプタを監視する用途では効率が悪いため、Solarisの/dev/pollやFreeBSDのkqueueなど、非標準な代替インターフェイスが用意されてきた。
epollはそれらと同様に、select/pollの代替となるべく追加されたシステムコールである。当初のパッチはSolarisと同じようにデバイスファイルを通してアクセスするインターフェイスであったが、Linus氏がこれを嫌ったため現在のシステムコールという形になった。
epollはepoll_create、epoll_ctl、epoll_waitの3つのシステムコールから成っており、使用の手順は以下のようになる。
なお、epoll fdは通常のディスクリプタであり、解放処理はcloseシステムコールで行う。また、epoll_ctlを用いてほかのepoll fdに再帰的に登録することもできる。
select/pollインターフェイスを使用した場合、select/pollシステムコールを使用するたびに監視したいディスクリプタのリストをカーネルに渡す必要があり、これは大規模なサーバなどでは大きな負荷となる場合がある。また、select/pollシステムコールでは、どのイベントがどのディスクリプタで起こったのかを知るためにユーザー空間でディスクリプタのリストをスキャンする必要がある。だが、そもそもカーネルはこの情報を持っているはずであり、それを再度調べるのは無駄な処理である。
これに対してepollは、上記の2で一度登録を行えばそのディスクリプタを繰り返しepoll_waitで使用できる。また、発生したイベント数のオーダーで処理できるため、select/pollインターフェイスに比べて効率が良いといえる。
以上のように、select/pollインターフェイスの改良版といえるepollだが、/dev/pollやkqueueなど、ほかのOSで使われているインターフェイスと比べて特に優れている点は見当たらない。既存のインターフェイスのどれかと互換性のあるものにしておけば何かと便利だと思うのだが……。
Copyright © ITmedia, Inc. All Rights Reserved.