仮想CPUの状態は大きく分けて2種類あります。いつでも実行可能な状態にあるものと、そうでないものです。実行可能な状態にある仮想CPUの中の、幾つかが実CPUに割り付けられ、実際にドメインの実行を行います。このように、実CPUに割り当てられたドメインを実行状態にあるといいます(図2)。また、実行可能な状態で、実CPUに割り付けられていないものを実行可能状態といいます。
さらに、実行可能でない状態には2種類あります。1つは待機状態で、ドメインに実行すべき処理がなく、仮想CPUがアイドル状態になっているときです。そのドメインに対して何らかの事象が発生*すると、直ちに実行可能な状態に遷移することになります。もう1つは中断状態で、強制的に実行を停止させられている状態です。ドメイン0上の管理コマンドの指示によってこの状態に遷移します。
仮想CPUは、これら2つの状態を同時に持つことが可能です。待機状態で、かつ中断状態という状態があり得るからです。何らかの事象を待っている状態(待機状態)で、強制的に実行を中断されると、この状態になります。
ではさっそく、ドメインスケジューラ本体のコードを読んでみましょう(リスト1)。ドメインスケジューラは、それぞれの実CPU上で独立して動作します。ドメインスケジューラの仕事は、どのドメイン(仮想CPU)に実行権を与えるか判断を下し、ドメインディスパッチャを呼び出すことです。
ドメインスケジューラは、現在実行可能状態である仮想CPUから、最も実行に適するものを選び出すアルゴリズムとして、前述の2種類をXenでは用意しています。Xenの標準スケジューラで利用されているsedfアルゴリズム*を利用して(A4)、次に走行すべき仮想CPUの選択を行います(A6)。選択した仮想CPUは、ドメインスケジューラが動作している実CPU用のスケジューリング用データ構造に対して、次に走行する仮想CPUとして登録しておきます(A7)。
新しい仮想CPUに切り替える前に、幾つか行っておくべき仕事があります。1つは再スケジューリングの準備であり、もう1つはドメインの時刻の調整です。
再スケジューリングの準備としては、次回ドメインスケジューラを起動すべき予定時刻をタイマーに設定しておきます*(A9)。このタイマーは再スケジューリング専用のタイマーで、次に動作する仮想CPUの実行権が切れるときに、本関数(__enter_scheduler関数)をソフト割り込みハンドラとして呼び出します。その結果、再スケジューリングが行われます。
ドメインの時刻調整も考慮する必要があります。仮想CPUを時分割で動作させているため、仮想CPUの実行が中断している間にも、実時間はどんどん進んでいきます。仮想CPUが実行権を得て動作を開始するときに、仮想CPUの時刻と実際の時刻のずれを調整しなければなりません。
これから実行権を与えられる仮想CPUがアイドルドメインでなければ(A17)、仮想CPUの時刻調整を行い(A18)ます。また、これから動作する仮想CPUが停止しているうちにXenの時計が進んでいる場合は、仮想CPUに対して仮想タイマー割り込みを発生させます*(A20)。
A16では、仮想CPUの実行を中断するときに、その中断時刻を記録しています。こうすることで、次に実行を開始したとき、Xenの時計とずれが生じているかどうかを判断できます(A19)。
切り替える仮想CPUの用意が整ったら、最後にドメインディスパッチャ(context_switch関数)を呼び出して、仮想CPUのコンテキストを切り替えます(A21)。もし仮想CPUの切り替えが発生しないならば(A10)、ドメインディスパッチャを呼び出さずに、Xenの出口処理に制御を移します(A12)。
なお、これらドメインスケジューラが利用するデータ構造は、スピンロックで守られています(A1、A11、A15)。ドメインスケジューラは、それぞれの実CPU上で独立して動作できるよう、スケジューリングに必要なデータ構造(schedule_data配列)とスピンロックを、それぞれの実CPUごとに用意しています。この後、リスト2のコードで、指定された仮想CPUをランキューに入れます。
スケジューリングの主要な処理は以上です。最後に、ドメインスケジューリング関係の重要な関数をまとめておきましょう(表1)。
関数名 | 説明 |
---|---|
__enter_scheduler() | ドメインスケジューラ本体 |
do_yield() | 再スケジューリング依頼 |
do_block() | カレントの仮想CPUを待機状態に遷移 |
vcpu_unblock() | 仮想CPUの起床 |
context_switch() | 仮想CPUの切り替え |
vcpu_pause() | 仮想CPUの実行中断 |
vcpu_unpause() | 仮想CPUの実行中断を解除 |
domain_pause() | ドメインの実行中断。そのドメインに属する仮想CPUすべての実行を中断する |
domain_unpause() | ドメインの実行中断を解除。そのドメインに属する仮想CPUすべての実行中断を解除する |
vcpu_runnable() | 指定した仮想CPUが実行可能状態にあるかどうかを調べる |
事象の通知には割り込みが使われる。
sedfアルゴリズムについては、次回詳しく説明する。
もちろん古いタイマーが登録されていれば、停止しておく必要もある(A2)。
これら機能に関しては、時計の回に詳しく触れることにする。
本記事は、オープンソースマガジン2006年6月号「仮想マシンモニタ Xen 3.0解読室」を再構成したものです。
Copyright © ITmedia, Inc. All Rights Reserved.