本实验依赖实验1/2/3/4。请把你做的实验1/2/3/4的代码填入本实验中代码中有“LAB1”/“LAB2”/“LAB3”/“LAB4”的注释相应部分。注意:为了能够正确执行lab5的测试应用程序,可能需对已完成的实验1/2/3/4的代码进行进一步改进。
do_execv函数调用load_icode(位于kern/process/proc.c中)来加载并解析一个处于内存中的ELF执行文件格式的应用程序,建立相应的用户内存空间来放置应用程序的代码段、数据段等,且要设置好proc_struct结构中的成员变量trapframe中的内容,确保在执行此进程后,能够从应用程序设定的起始执行地址开始执行。需设置正确的trapframe内容。
实现过程
答:load_icode()函数可以加载处于内存中的ELF文件;主要步骤如下:
调用mm_create()函数来申请进程内存管理结构mm所需的内存空间,并对mm进行初始化;
描述当创建一个用户态进程并加载了应用程序后,CPU是如何让这个应用程序最终在用户态执行起来的。即这个用户态进程被ucore选择占用CPU执行(RUNNING态)到具体执行应用程序第一条指令的整个经过。
答:
在函数load_icode()之后,用户进程的用户环境已经搭建完毕,此时,initproc将按产生系统调用的函数调用路径返回,中断执行iret,将切换到用户进程的第一条语句(根据tf_eip的值)。
创建子进程的函数do_fork在执行中将拷贝当前进程(即父进程)的用户内存地址空间中的合法内容到新进程中(子进程),完成内存资源的复制。具体是通过copy_range函数(位于kern/mm/pmm.c中)实现的,请补充copy_range的实现,确保能够正确执行。
答:在copy_range时,并不进行复制,只是将pde_t * to赋值为pde_t * from,并将该页的COPY_ON_WRITE位置1(只读),在需要写时会产生缺页错误,此时才将内存中的内容进行复制
理解进程执行 fork/exec/wait/exit 的实现,以及系统调用的实现(不需要编码)
请在实验报告中简要说明你对 fork/exec/wait/exit函数的分析。并回答如下问题:
答:当程序执行fork(),exec(),wait(),exit()函数时,会调用sys_xxxx()函数,这些函数又会调用syscall()函数,syscall()函数嵌入了内联汇编指令,int产生系统调用与中断。
而kernel则会对这些系统调用进行统一的处理。这些函数会产生中断,如果此时current -> need_resched ==1,则会进行调度。
答:进程创建(fork()函数) -> 进程就绪(proc -> state == RUNNABLE)-> 进程执行(schedule()函数) -> 进程退出(do_exit()) -> 进程结束(do_wait()回收kstack和proc_struct)
| (schedule()函数) |
|______________________________________|