// Challenge! int sfork(void) { int r; pde_t *pde; pte_t *pte; unsigned i; uint32_t addr; envid_t envid; envid = sys_exofork();//创建子环境 if(envid < 0) panic("sys_exofork: %e", envid); if(envid==0)//子环境中 { env = &envs[ENVX(sys_getenvid())]; return 0; } else{//父环境中,注意:这里需要设置父环境的缺页异常栈,还需要设置子环境的缺页异常栈, //父子环境的页异常栈不共享?具体原因还得思考 env = &envs[ENVX(sys_getenvid())]; set_pgfault_handler(pgfault);//设置缺页异常处理函数,这里设置了父环境的缺页异常栈 for(i=0;i<(unsigned)VPN(UTOP);i++)//重映射writable or copy-to-write的页面 { addr=i*PGSIZE; pde =(pde_t*) &vpd[VPD(addr)]; if(*pde&PTE_P)//这里只处理有物理页面映射的页表项 { pte=(pte_t*)&vpt[VPN(addr)]; } else continue; if((i==(unsigned)VPN(USTACKTOP-PGSIZE))||(i==(unsigned)VPN(PFTEMP))) //特殊处理,用户层普通栈 { if((r=duppage(envid,i))<0) return r; continue; } if((r=sduppage(envid,i))<0) return r; } if((r=sys_page_alloc(envid,(void*)(UXSTACKTOP-PGSIZE),PTE_W|PTE_U|PTE_P))<0) return r;//设置子环境的缺页异常栈 if((r=sys_env_set_pgfault_upcall(envid,(void*)_pgfault_upcall))<0) return r;//设置子环境的缺页异常处理入口点 if((r=sys_env_set_status(envid,ENV_RUNNABLE))<0) return r;//设置子环境的状态为可运行 return envid; } //panic("sfork not implemented"); //return -E_INVAL; }
// Challenge! int sfork(void) { /* panic("sfork not implemented"); return -E_INVAL;*/ extern void _pgfault_upcall(void); set_pgfault_handler(pgfault); envid_t id = sys_exofork(); int r; if (id < 0) panic("exofork: child"); if (id == 0) { thisenv = envs + ENVX(sys_getenvid()); return 0; } uint32_t i; /* for (i=0;i<UTOP-PGSIZE;i+=PGSIZE) if ((vpd[PDX(i)] & PTE_P) && (vpt[PGNUM(i)] & PTE_P)) if ((r=duppage(id,PGNUM(i)))<0) return r;*/ if ((r=sys_page_alloc(id, (void*)(UXSTACKTOP-PGSIZE), PTE_U | PTE_W | PTE_P))<0) return r; // cprintf("begin to map!\nUSTACKTOP-PGSIZE: %x\nUTEXT: %x\n",USTACKTOP-PGSIZE,UTEXT); for (i=USTACKTOP-PGSIZE;i>=UTEXT;i-=PGSIZE) { if ((vpd[PDX(i)] & PTE_P) && (vpt[PGNUM(i)] & PTE_P)) { if ((r=sduppage(id,PGNUM(i),1))<0) return r; }else break; } for (;i>=UTEXT;i-=PGSIZE) if ((vpd[PDX(i)] & PTE_P) && (vpt[PGNUM(i)] & PTE_P)) if ((r=sduppage(id,PGNUM(i),0))<0) return r; if ((r=sys_env_set_pgfault_upcall(id,(void*)_pgfault_upcall))<0) return r; if ((r=sys_env_set_status(id, ENV_RUNNABLE))<0) return r; // cprintf("sfork succeed!\n"); return id; }