操作系统实验报告
班级:计算机科学与技术
姓名: 学号:
实验3 进程的创建
一、实验目的
练习使用 EOS API 函数 CreateProcess 创建一个进程,掌握创建进程的方法,理解进程和程序的区别。
调试跟踪 CreateProcess 函数的执行过程,了解进程的创建过程,理解进程是资源分配的单位。
二、实验过程记录
1.
/*Hello.c*/
#include \
int main(int argc, char* argv[]) { int i; for (i = 1; i <= 5; i++) { printf(\ Sleep(1000); } printf(\ return 0; }
作用:测试软盘镜像中的程序。输出\并循环输出五次,每次挂起1000ms,最后输出” Bye-bye!”。 结果:
2.
/*NewProc.c*/
#include \
int main(int argc, char* argv[]) { STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcInfo;
ULONG ulExitCode; // 子进程退出码 INT nResult = 0; // main 函数返回值。0 表示成功,非 0 表示失败。 #ifdef _DEBUG __asm(\#endif printf(\ // // 使子进程和父进程使用相同的标准句柄。 // StartupInfo.StdInput = GetStdHandle(STD_INPUT_HANDLE); StartupInfo.StdOutput = GetStdHandle(STD_OUTPUT_HANDLE); StartupInfo.StdError = GetStdHandle(STD_ERROR_HANDLE); //
// 创建子进程。 //
if (CreateProcess(\ // // 创建子进程成功,等待子进程运行结束。 // WaitForSingleObject(ProcInfo.ProcessHandle, INFINITE); //
// 得到并输出子进程的退出码。 //
GetExitCodeProcess(ProcInfo.ProcessHandle, &ulExitCode); printf(\//
// 关闭不再使用的句柄。 // CloseHandle(ProcInfo.ProcessHandle); CloseHandle(ProcInfo.ThreadHandle); } else { printf(\ nResult = 1; } return nResult; }
作用:软盘镜像引导成功后自动执行EOSAPP.exe,创建父进程,然后父进程首先开始执行并输出内容,父进程创建了子进程(Hello.exe)后,子进程开始执行并输出内容,待子进程结束后父进程再继续执行。 结果:
调试 CreateProcess 函数
1)按 F5 启动调试 EOS 应用程序,OS Lab 会首先弹出一个调试异常对话框。 2)选择“是”调试异常,调试会中断。
3)在 main 函数中调用 CreateProcess 函数的代码行(第 57 行)添加一个断点。 4)按 F5 继续调试,在断点处中断。
5)按 F11 调试进入 CreateProcess 函数。此时已经开始进入 EOS 内核进行调试.
验证:验证了了一个进程可以包含多个程序,该父进程包含了 eosapp.exe 和 kernel.dll 两个程序; 内核(kernel.dll)处于高 2G 的虚拟地址空间中; 应用程序(eosapp.exe)处于低 2G 的虚拟地址空间中.
数据展示: CreateProcess 函数的指令的虚拟地址都大于 0x80000000; main 函数的指令所在的虚拟地址都是小于 0x80000000. 调试 PsCreateProcess 函数 调试 PspCreateProcessEnvironment 函数 1.在 PsCreateProcess 函数中找到调用 PspCreateProcessEnvironment 函数的代码行 (create.c文件的第 163 行),并在此行添加一个断点。 2.按 F5 继续调试,到此断点处中断。 3.按 F11 调试进入 PspCreateProcessEnvironment 函数。 调试进程控制块的创建过程: 1.在调用 ObCreateObject 函数的代码行(create.c 文件的第 418 行)添加一个断点。 2.按 F5 继续调试,到此断点处中断。 3.按 F10 执行此函数后中断。 4.此时为了查看进程控制块中的信息,将表达式*NewProcess 添加到“监视”窗口中。 5.将鼠标移动到“监视”窗口中此表达式的“值”属性上,会弹出一个临时窗口,在临 时窗口中会按照进程控制块的结构显示各个成员变量的值(可以参考 PROCESS 结构体 的定义)。由于只是新建了进程控制块,还没有初始化其中成员变量,所以值都为 0。 接下来调试初始化进程控制块中各个成员变量的过程: 1.首先创建进程的地址空间,即 4G 虚拟地址空间。在代码行(create.c 文件的第 437 行)
NewProcess->Pas = MmCreateProcessAddressSpace();
添加一个断点。 2.按 F5 继续调试,到此断点处中断。 3.按 F10 执行此行代码后中断。 4.在“监视”窗口中查看进程控制块的成员变量 Pas 的值已经不再是 0。说明已经初 始化了进程的4G 虚拟地址空间。 5.使用 F10 一步步调试 PspCreateProcessEnvironment 函数中后面的代码,在调试的过 程中根据执行的源代码,查看“监视”窗口中*NewProcess 表达式的值,观察进程控制 块中哪些成员变量是被哪些代码初始化的,哪些成员变量还没有被初始化。 6.当从 PspCreateProcessEnvironment 函数返回到 PsCreateProcess 函数后,停止按 F10。此时“监视”窗口中已经不能再显示表达式*NewProcess 的值了,在 PsCreateProcess 函数中是使用ProcessObject 指针指向进程控制块的,所以将表达式*ProcessObject 添 加到“监视”窗口中就可以继续观察新建进程控制块中的信息。 7.接下来继续使用 F10 一步步调试 PsCreateProcess 函数中的代码,同样要注意观察执 行后的代码修改了进程控制块中的哪些成员变量。当调试到 PsCreateProcess 函数的最 后一行代码时,查看进程控制块中的信息,此时所有的成员变量都已经被初始化了(注 意观察成员 ImageName 的值)。 8.按 F5 继续执行,EOS 内核会为刚刚初始化完毕的进程控制块新建一个进程。激活虚 拟机窗口查看新建进程执行的结果。 9.在 OS Lab 中选择“调试”菜单中的“停止调试”结束此次调试。 10.选择“调试”菜单中的“删除所有断点”。
验证:在PsCreateProcess 函数中首先调用了 PspCreateProcessEnvironment 函数来创建进程控制块. ObCreateObject 函数会在由 EOS 内核管理的内存中创建了一个新的进程控制块(也就是分配了一块内存),并由 NewProcess 返回进程控制块的指针(也就是所分配内存的起始地址)
数据展示:ObCreateObject 函数创建新的进程控制块时*NewProcess, 还没有初始化其中成员变量,所以值都为 0。初始化进程控制块中各个成员变量的过程中, 进程控制块的成员变量 Pas 的值已经不再是0。 3.
/* NewTwoProc.c*/ #include \
int main(int argc, char* argv[]) { STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcInfoOne, ProcInfoTwo; ULONG ulExitCode; // 子进程退出码 INT nResult = 0; // main 函数返回值。0 表示成功,非 0 表示失败。 #ifdef _DEBUG __asm(\#endif printf(\ // // 使子进程和父进程使用相同的标准句柄。 //