练习0:填写已有实验
请把你做的实验1/2/3/4的代码填入本实验中代码中有“LAB1”,“LAB2”,“LAB3”,”LAB4”的注释相应部分。注意:为了能够正确执行lab5的测试应用程序,可能需对已完成的实验1/2/3/4的代码进行进一步改进。
1 | 这几个文件补上 说真的最烦这个步骤 但是这次 不只是直接复制 还要补充 |
以下为补充的代码块
1 | proc.c: |
练习1: 加载应用程序并执行
do_execv函数调用load_icode(位于kern/process/proc.c中)来加载并解析一个处于内存中的ELF执行文件格式的应用程序,建立相应的用户内存空间来放置应用程序的代码段、数据段等,且要设置好proc_struct结构中的成员变量trapframe中的内容,确保在执行此进程后,能够从应用程序设定的起始执行地址开始执行。需设置正确的trapframe内容。
请在实验报告中简要说明你的设计实现过程。
1 | 以下为要填写的内容 首先清空进程原先的中断帧 然后再将 中断帧中的 代码段 和 数据段 |
请在实验报告中描述当创建一个用户态进程并加载了应用程序后,CPU是如何让这个应用程序最终在用户态执行起来的。即这个用户态进程被ucore选择占用CPU执行(RUNNING态)到具体执行应用程序第一条指令的整个经过。
在此之前先理一下 用户态进程是怎么来的
- 创建了一个 硬构造了 第0个 内核线程 idleproc
- idleproc 通过
kernel_thread
创建了 第1个内核线程 initproc 在 lab 4 中只是打印字符串 - initproc 通过
kernel_execve
将 hello应用程序执行码覆盖到了 initproc 用户虚拟内存空间 来创建 用户态进程
1 | 创建一个用户态进程并加载了应用程序之后 调度器 schedule 调用 proc_run |
练习2: 父进程复制自己的内存空间给子进程
创建子进程的函数do_fork在执行中将拷贝当前进程(即父进程)的用户内存地址空间中的合法内容到新进程中(子进程),完成内存资源的复制。具体是通过copy_range函数(位于kern/mm/pmm.c中)实现的,请补充copy_range的实现,确保能够正确执行。
1 | 这个函数是用来 拷贝父进程的用户内存地址空间到子进程中 share 此处没用到 不管它 |
练习3: 阅读分析源代码,理解进程执行 fork/exec/wait/exit 的实现,以及系统调用的实现
请在实验报告中简要说明你对 fork/exec/wait/exit函数的分析。并回答如下问题:
- 请分析fork/exec/wait/exit在实现中是如何影响进程的执行状态的?
1 | fork 创建新的 PCB 进程状态为 UNINIT |
- 请给出ucore中一个用户态进程的执行状态生命周期图(包执行状态,执行状态之间的变换关系,以及产生变换的事件或函数调用)
1 | RUNNING----------------+ |
最后附上运行结果 做这个 lab 的时候 给绕的很晕 要特别注意 各个函数 分别修改了 中断帧 和 上下文的 eip esp 的哪些内容
比如 kernel_thread
将 tf->eip
设置为 kernel_thread_entry
当此进程被调度上去的时候
就会跳到 kernel_thread_entry
去执行 fn
这个函数copy_thread
将 tf->eip
设置为 forkret
而 forkret
会执行这条指令 movl 4(%esp), %esp
将 context->esp
当做 栈顶
而 context->esp
又在 copy_thread 中 被设置为 中断帧的栈顶