戦略ソフトウェア特論II - Virtual Memory 補足資料
TA   栗原 一貴(kurihara@ynl.t.u-tokyo.ac.jp), 小林 義徳(yoshinor@yl.is.s.u-tokyo.ac.jp)
課題

Virtual Memory課題ファイル(VMExercises.pdf)
の、各Question および Experiment を全て解いてください。
Experiment については、以下を参考にしてください。

この課題は、DDK でなく、Borland C/C++ Compiler や Visual C++ などを使ってもできます。

※ 提出方法・単位についてはこちら

Experiment 5

この課題は、ページフォルトのハンドラを書く練習です。
問題文中にある、tokyo_vm.exe は、以下のアーカイブに入っています。

virtualmemory.zip
[内容] tokyo_vm.exe
tokyodemo.dll
tokyodemo.h
tokyodemo.lib

また、TokOSLaunchFaultingProcess (内部で tokyo_vm.exe を呼び出す関数) は、同じアーカイブ内の tokyodemo.h で宣言されており、関数の実体はtokyodemo.dll に入っています。
TokOSLaunchFaultingProcess のプロトタイプ宣言は以下の通りです。

				  
typedef BOOL (*TOK_PAGE_FAULT_HANDLER_FN)(IN PPAGE_FAULT_INFO PageFaultInfo);

DWORD 
TokOSLaunchFaultingProcess(
    IN TOK_PAGE_FAULT_HANDLER_FN Handler,    // ページフォルトのハンドラ
    IN TCHAR *argv[]                         // tokyo_vm.exe に渡す引数
);

課題としては、以下のようなプロトタイプのページフォルトのハンドラを作成してもらうことになります。


BOOL
PageFaultHandler(
    IN PPAGE_FAULT_INFO PageFaultInfo
);

これを第一引数として、TokOSLaunchFaultingProcess を呼び出すことになります。

以下は課題のやり方の一例です。

(1) tokyo_vm.exe をコマンドラインより起動し、渡すべきコマンドライン・オプションを確認してください。
(2)

とりあえず tokyodemo.dll 内の TokOSLaunchFaultingProcess を呼び出すプログラムを作成してください。
TokOSLaunchFaultingProcess は、内部で CreateProcess API を使って tokyo_vm.exe を呼び出しています。
その際に、tokyo_vm.exe でページフォルトが起こった場合、第一引数として渡したハンドラが呼ばれるようになっています。

やりかたとしては、下の (a), (b) のどちらを使ってもかまいません。

(a) アーカイブ内部の tokyodemo.lib を dll のインポート・ライブラリとして使うやり方。
(tokyodemo.h をインクルードし、tokyodemo.lib をプログラムにリンクするだけ、というやりかた。
起動時に tokyodemo.dll がないとプログラムが起動しません)。
おそらく、Microsoft C/C++ (cl.exe) 限定だと思います。
(b) プログラム中で tokyodemo.dll 内の TokOSFaultingProcess を直接ロードし、それを呼び出すやり方(下の例を参照)。

#include "tokyodemo.h"

typedef DWORD (__stdcall *FUNC)(
    IN TOK_PAGE_FAULT_HANDLER_FN Handler,    // ページフォルトのハンドラ
    IN TCHAR *argv[]                         // tokyo_vm.exe に渡す引数
);

int main(int argc, char** argv)
{
    FUNC func;
    HMODULE hDll;

    hDll = LoadLibrary("tokyodemo.dll");
    if(!hDll){
        printf("tokyodemo.dll not found.\n");
        exit(1);
    }
    func = (FUNC)GetProcAddress(hDll,"TokOSLaunchFaultingProcess");
    if(!func){
        printf("cannot load TokOSLaunchFaultingProcess.\n");
        exit(1);
    }
    (*func)(NULL, argv);     // ハンドラをまだ書いてないのでとりあえず第一引数は NULL にしてあります。

    return 0;
}
                      
C コンパイラとして、マイクロソフト製の cl.exe 以外(たとえば Borland C++)を使っている場合は、(b)を使うことになると思います。
(3) ページフォルトのハンドラを作成し、(2) で作ったプログラムで TokOSLaunchFaultingProcess の第一引数に使ってみてください。
					   
BOOL
PageFaultHandler(
    IN PPAGE_FAULT_INFO PageFaultInfo
);

[ハンドラ内では、以下の処理を行うこと]
(a) ページフォルトがスタックで生じた場合(本文中では demand-zero stack fault とある)。
(a-1) フォルトが起こったあたりの仮想アドレス領域を物理メモリにマップする。
(b) 命令を読みに行った時にページフォルトが起こった場合(本文中では、demand-code page fault とある)。
(b-1) フォルトが起こったあたりの仮想アドレス領域を物理メモリにマップ。
(b-2) フォルトが起こったアドレス以降の領域に、TokGetCodeBuffer (tokyodemo.dll にある) で取得したデータ(実は機械語でかかれたプログラム) をコピー。
(b-3) 命令キャッシュをフラッシュ。

(a),(b) いずれの場合も、正しく処理できた場合は return TRUE, そうでない場合は return FALSE するように作ってください。

API は、以下のものを使ってください。

フォルトが上の (a), (b) のどちらであるかを判断するための情報を取得: GetThreadContext
ページサイズの取得: GetSystemInfo
仮想アドレス領域の、物理メモリへのマップ: VirtualAlloc または VirtualAllocEx
TokGetCodeBuffer で取得したバッファのコピー: WriteProcessMemory
命令キャッシュをフラッシュ: FlushInstructionCache

tokyo_vm.exe のプロセス ID などは、ハンドラの引数の、PageFaultInfo から取得することができます。

TokGetCodeBuffer (tokyodemo.dll 内に実体がある)
					   
PVOID
TokGetCodeBuffer(
    OUT PDWORD NumCodeBytes
);

返り値は、機械語プログラムの書かれたバッファの先頭へのポインタ( PVOID = void* )
また、引数として、 DWORD 型の変数へのポインタを渡すと、そこに バッファの長さが格納される。
        (DWORD  = unsigned long (32 bit), PDWORD = DWORD*) 
                      
(4)

正しくハンドラが書けると、TokOSLaunchFaultingProcess を介して呼ばれた tokyo_vm.exe が、入力に対し、ある値を返してきます。

					   
例)  Congratulations! tokyo_vm.exe executed correctly, yielding 3. 

様々に入力パラメータを変えて出力を観測し、tokyo_vm.exe が何を計算しているのか答えてください。

Experiment 6

並列プログラミングの教科書に必ず載っている、生産者・消費者問題のプログラムを、本文の指示にしたがって Windows 上で実装してください。

ヒント
(1) 改行を待たずにコンソールより文字を読み込む関数:
_getch() (エコーあり) または _getche() (エコーあり) (いずれも <conio.h> )
(2) ファイルマッピングを介してプロセス間共有メモリを実現:
CreateFile, CreateFileMapping, MapViewOfFile (または MapViewOfFileEx) API を使用。

不明な点があったら、栗原 一貴(kurihara@ynl.t.u-tokyo.ac.jp), 小林 義徳(yoshinor@yl.is.s.u-tokyo.ac.jp) にメールで連絡してください。
また、ディビッド・プロバード先生のメールアドレスは,davepr@microsoft.com となっているので,授業についての質問などはそこにメールしてください.

TOPへ戻る