第六章. 系统调度,COW Fork和IPC (lab4)
提纲 多用户环境调度 COW Fork (写时拷贝环境创建) 用户环境间通讯(IPC)
多用户环境调度 Idle 环境及yield RR (Round-Robin) Scheduling 子进程的创建(Dumb Fork)
多用户环境调度(续) Idle 用户环境 #include <inc/x86.h> #include <inc/lib.h> void umain(void) { binaryname = "idle"; while (1) { sys_yield(); breakpoint(); }
多用户环境调度(续) sys_yield的执行路线
多用户环境调度(续) yield 放弃本用户环境的执行 选择“适当”的用户环境投入运行 “适当”应该根据具体的调度算法进行
多用户环境调度(续) RR (Round-Robin) Scheduling 循环轮转算法 应该寻找除了释放CPU的当前用户环境(curenv)和idle用户环境之外的“下一个”用户环境投入运行(采用env_run),在找不到的情况下将idle用户环境投入运行(breakpoint)。 由于idle用户环境占据了envs[0],应该在envs[1]到envs[NENV-1]之间寻找“下一个”用户环境。 完成sched_yield(void)函数
多用户环境调度(续) 子进程的创建(Dumb Fork) 完成sys_exofork(void)函数 分配用户环境管理数据结构 将创建的子环境的上下文设置为当前用户环境的上下文 设置创建的子环境的状态为ENV_NOT_RUNNABLE 完成空间分配和映射等辅助函数 sys_env_set_status (设置状态) sys_page_alloc (为用户态环境分配页面) sys_page_map (建立页面的映射关系) sys_page_unmap (取消页面的映射关系)
多用户环境调度(续) Dumb Fork (user/dumbfork.c) 思考: 如何让父环境在调用sys_exofork( ) 后返回子环境的envid,而子环境返回0? 如何通过页面分配和拷贝实现子用户环境的运行? UTEMP的作用是什么?这里能不能用UTOP? 修改kern/init.c运行dumbfork.c
COW Fork COW的概念 User Trap Frame的设置 用户态页面失效处理 Fork
COW Fork(续) COW的概念 在dumb fork中,JOS采用的是全拷贝的方法(从UTEXT到end)来运行子环境 然而通过复制父环境的方法来提供子环境的运行上下文会是相当重负载的 特别是当子环境创建后,需要加载不同于父环境的代码和数据开始运行的情况(如通过Shell的exec创建的子环境) 考虑三种类型的段:代码段、数据段(包括附加数据段)、堆栈段。其中代码段是完全不需要拷贝的,只需要映射即可。 采用写时复制技术(即当有数据更新的时候才复制整个被写的页面)来完成子环境的创建
COW Fork(续) COW的概念(续) 因为写时复用技术的采用,就需要对子环境对页面的写操作进行截获 完成这项工作,最简单的办法就是利用缺页中断 JOS中采用的是用户级缺页中断处理的方法 在子环境的管理数据结构中定义回调函数env_pgfault_upcall,用户环境通过调用sys_env_set_pgfault_upcall系统调用来设置自己的缺页中断处理函数,并让内核态的中断处理过程调用被登记的中断处理函数。 思考:JOS采用这种用户级的缺页处理方法的优缺点是什么?
COW Fork(续) User Trap Frame的设置 思考: 完成: 1. 为什么要设置User Trap Frame? 3. 如何判断是不是nested page fault 4. 当从内核态回到用户态的时候,如何跳到用户态的页面失效处理函数入口? 完成: lib/pgfault.c的set_pgfault_handler( void (*handler)(struct UTrapframe *utf)) kern/syscall.c的 sys_env_set_pgfault_upcall (envid_t envid, void *func) kern/trap.c的page_fault_handler (struct Trapframe *tf)
COW Fork(续) 用户态页面失效处理 注意:用户态页面失效处理过程的入口是lib/pfentry.S中的_pgfault_upcall,而不是用户环境注册的处理handler。 这样做的原因,是对用户注册的处理handler进行包装,确保在handler处理完成后,系统回到“正确的位置”继续执行。 完成: _pgfault_upcall函数 faultread、faultdie、faultalloc三个测试。注意faultalloc所导致的嵌套页面失效以及处理 思考:这里“正确的位置”指的是哪些位置?
COW Fork(续) Fork 完成: 思考: lib/fork.c中的fork(void) lib/fork.c中的duppage(envid_t envid, unsigned pn) lib/fork.c中的pgfault(struct UTrapframe *utf) user/forktree测试 思考: 1. 在创建子环境,并“复制”父环境的上下文的过程中,为什么需要将父环境的页面属性也设置为PTE_COW?这样做有没有例外?
用户环境间通讯(IPC) 完成: lib/ipc.c中的ipc_send(envid_t to_env, uint32_t val, void *pg, int perm)函数 lib/ipc.c中的ipc_recv(envid_t *from_env_store, void *pg, int *perm_store)函数 kern/syscall.c中的sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm) kern/syscall.c中的sys_ipc_recv(void *dstva) 思考: Send和Receive这两个动作,哪个是block的?JOS系统如何实现这种blocking?
本章结束