Experiment 5
この課題は、ページフォルトのハンドラを書く練習です。
問題文中にある、tokyo_vm.exe は、以下のアーカイブに入っています。
また、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へ戻る |