操作系统实验报告班级:计算机科学与技术姓名:学号:实验3进程的创建一、实验目的练习使用EOSAPI函数CreateProcess创建一个进程,掌握创建进程的方法,理解进程和程序的区别。调试跟踪CreateProcess函数的执行过程,了解进程的创建过程,理解进程是资源分配的单位。二、实验过程记录1./*Hello.c*/#includeEOSApp.hintmain(intargc,char*argv[]){inti;for(i=1;i=5;i++){printf(Hello,world!%d\n,i);Sleep(1000);}printf(Bye-bye!\n);return0;}作用:测试软盘镜像中的程序。输出Hello,world!I”并循环输出五次,每次挂起1000ms,最后输出”Bye-bye!”。结果:2./*NewProc.c*/#includeEOSApp.hintmain(intargc,char*argv[]){STARTUPINFOStartupInfo;PROCESS_INFORMATIONProcInfo;ULONGulExitCode;//子进程退出码INTnResult=0;//main函数返回值。0表示成功,非0表示失败。#ifdef_DEBUG__asm(int$3\nnop);#endifprintf(Createaprocessandwaitfortheprocessexit...\n\n);////使子进程和父进程使用相同的标准句柄。//StartupInfo.StdInput=GetStdHandle(STD_INPUT_HANDLE);StartupInfo.StdOutput=GetStdHandle(STD_OUTPUT_HANDLE);StartupInfo.StdError=GetStdHandle(STD_ERROR_HANDLE);////创建子进程。//if(CreateProcess(A:\\Hello.exe,NULL,0,&StartupInfo,&ProcInfo)){////创建子进程成功,等待子进程运行结束。//WaitForSingleObject(ProcInfo.ProcessHandle,INFINITE);////得到并输出子进程的退出码。//GetExitCodeProcess(ProcInfo.ProcessHandle,&ulExitCode);printf(\nTheprocessexitwith%d.\n,ulExitCode);////关闭不再使用的句柄。//CloseHandle(ProcInfo.ProcessHandle);CloseHandle(ProcInfo.ThreadHandle);}else{printf(CreateProcessFailed,Errorcode:0x%X.\n,GetLastError());nResult=1;}returnnResult;}作用:软盘镜像引导成功后自动执行EOSAPP.exe,创建父进程,然后父进程首先开始执行并输出内容,父进程创建了子进程(Hello.exe)后,子进程开始执行并输出内容,待子进程结束后父进程再继续执行。结果:调试CreateProcess函数1)按F5启动调试EOS应用程序,OSLab会首先弹出一个调试异常对话框。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.在OSLab中选择“调试”菜单中的“停止调试”结束此次调试。10.选择“调试”菜单中的“删除所有断点”。验证:在PsCreateProcess函数中首先调用了PspCreateProcessEnvironment函数来创建进程控制块.ObCreateObject函数会在由EOS内核管理的内存中创建了一个新的进程控制块(也就是分配了一块内存),并由NewProcess返回进程控制块的指针(也就是所分配内存的起始地址)数据展示:ObCreateObject函数创建新的进程控制块时*NewProcess,还没有初始化其中成员变量,所以值都为0。初始化进程控制块中各个成员变量的过程中,进程控制块的成员变量Pas的值已经不再是0。3./*NewTwoProc.c*/#includeEOSApp.hintmain(intargc,char*argv[]){STARTUPINFOStartupInfo;PROCESS_INFORMATIONProcInfoOne,ProcInfoTwo;ULONGulExitCode;//子进程退出码INTnResult=0;//main函数返回值。0表示成功,非0表示失败。#ifdef_DEBUG__asm(int$3\nnop);#endifprintf(Createtwoprocessesandwaitfortheprocessesexit...\n\n);////使子进程和父进程使用相同的标准句柄。//StartupInfo.StdInput=GetStdHandle(STD_INPUT_HANDLE);StartupInfo.StdOutput=GetStdHandle(STD_OUTPUT_HANDLE);StartupInfo.StdError=GetStdHandle(STD_ERROR_HANDLE);////为一个应用程序同时创建两个子进程。//if(CreateProcess(A:\\Hello.exe,NULL,0,&StartupInfo,&ProcInfoOne)&&CreateProcess(A:\\Hello.exe,NULL,0,&StartupInfo,&ProcInfoTwo)){////创建子进程成功,等待子进程运行结束。//WaitForSingleObject(ProcInfoOne.ProcessHandle,INFINITE);WaitForSingleObject(ProcInfoTwo.ProcessHandle,INFINITE);////得到并输出子进程的退出码。//GetExitCodeProcess(ProcInfoOne.ProcessHandle,&ulExitCode);printf(\nTheprocessoneexitwith%d.\n,ulExitCode);GetExitCodeProcess(ProcInfoTwo.ProcessHandle,&ulExitCode);printf(\nTheprocesstwoexitwith%d.\n,ulExitCode);////关闭不再使用的句柄。//CloseHandle(ProcInfoOne.ProcessHandle);CloseHandle(ProcInfoOne.ThreadHandle);CloseHandle(ProcInfoTwo.ProcessHandle);CloseHandle(ProcInfoTwo.ThreadHandle);}else{printf(CreateProcessFailed,Errorcode:0x%X.\n,GetLastError());nResult=1;}returnnResult;}作用:在eosapp.exe父进程下,为hello.exe创建两个子进程,分别等待两个子进程结束,得到退出码后关闭句柄。结果:交替分别显示两遍Hello,world!(1~5)”以及”Bye-bye!”。三、思考与练习3.在PsCreateProcess函数中调用了PspCreateProcessEnvironment函数后又先后调用了PspLoadProcessImage和PspCreateThread函数,学习这些函数的主要功能。能够交换这些函数被调用的顺序吗?思考其中的原因。答:PspCreateProcessEnvironment的主要功能是创建进程控制块,并且为进程创建地址空间和分配句柄表。PspLoadProcessImage是将进程的可执行映像加载到进程的地址空间中。PspCreateThread创建了进程的主线程。这三个函数被调用的顺序是不能够改变的。加载可执行映像之前必须已经为进程分配了地址空间,这样才能够确定可执行映像可以被加载到内存的位置;在创建主线程之前必须已经加载过可执行映像,这样主线程才知道指令分工以及开始执行的位置。因此不能交换他们的顺序。四、备注说明在机房完成。实验5进程的同步一、实验目的使用