【xv6 源码窥探(2)】懒分配策略
前言
- 本篇是关于 MIT 6.S081-2020-Lab5 的实现;
- 如果内容上发现有什么问题请不要吝啬您的键盘。
Lazy allocation 的想法在之前在做页表实验的最后提到了,所以这次实验同样可以吃老本快速过关。
跟着提示做基本不会遇到问题,只有在最后有一个容易踩坑的地方。
先是修改
sys_sbrk
的实现:/* kernel/sysproc.c */uint64
sys_sbrk(void)
{
int addr;
int n;
struct proc *p = myproc();
if(argint(0, &n) < 0)
return -1;
addr = p->sz;
if(n < 0){
uvmdealloc(p->pagetable, addr, addr + n);
}p->sz += n;
return addr;
}
再是处理 page-fault 异常中断:
/* kernel/trap.c */void
usertrap(void)
{
...
} else if (r_scause() == 13 || r_scause() == 15) {
uint64 va = r_stval();
uint64 sp = PGROUNDUP(p->trapframe->sp);
if (va >= p->sz || va < sp) {
p->killed = 1;
} else {
va = PGROUNDDOWN(va);
char *pa = kalloc();
if(pa != 0){
memset(pa, 0, PGSIZE);
if(mappages(p->pagetable, va, PGSIZE, (uint64)pa, PTE_W|PTE_X|PTE_R|PTE_U) != 0){
kfree(pa);
}
} else {
p->killed = 1;
}
}
} else if((which_dev = devintr()) != 0){
...
}
接着不要让
uvmcopy
和 uvmunmap
panic。如果只是为了过 lazytests 和 usertests 的话,不用判断 va 是否是 heap 区域直接 continue 就可以直接过。
严谨点的话还是写一下比较好。
/* kernel/vm.c */void
uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
{
...
for(a = va;
a < va + npages*PGSIZE;
a += PGSIZE){
if((pte = walk(pagetable, a, 0)) == 0)
continue;
// panic("uvmunmap: walk");
if((*pte & PTE_V) == 0)
// panic("uvmunmap: not mapped");
continue;
...
}int
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
{
...
for(i = 0;
i < sz;
i += PGSIZE){
if((pte = walk(old, i, 0)) == 0)
// panic("uvmcopy: pte should exist");
continue;
if((*pte & PTE_V) == 0)
continue;
// panic("uvmcopy: page not present");
...
}
最后的最后,不要忘记处理这个 Hint:
- Handle the case in which a process passes a valid address from sbrk() to a system call such as read or write, but the memory for that address has not yet been allocated.
所以就头铁直接跑 usertests,结果挂了一个 sbrkarg 测试点。
找了找看是什么问题,发现存在一个调用链:
sys_write
->filewrite
->writei
->either_copyout
->copyout
->walkaddr
。重点是在
walkaddr
函数内,如果发现一个 page 不存在或不可用,它只会返回 0,并不会产生 page-fault,也就不会被 usertrap 处理。所以这里还要给
walkaddr
额外添加一个处理逻辑。/* kernel/vm.c */// Look up a virtual address, return the physical address,
// or 0 if not mapped.
// Can only be used to look up user pages.
uint64
walkaddr(pagetable_t pagetable, uint64 va)
{
pte_t *pte;
uint64 pa;
struct proc *p = myproc();
if(va >= MAXVA)
return 0;
pte = walk(pagetable, va, 0);
if(pte == 0 || (*pte & PTE_V) == 0)
{
if (va >= p->sz || va < PGROUNDUP(p->trapframe->sp))
return 0;
if ((pa = (uint64)kalloc()) == 0)
return 0;
if (mappages(p->pagetable, PGROUNDDOWN(va), PGSIZE, pa, PTE_W|PTE_X|PTE_R|PTE_U) != 0) {
kfree((void*)pa);
return 0;
}
return pa;
}
if((*pte & PTE_U) == 0)
return 0;
pa = PTE2PA(*pte);
return pa;
}
后记 【【xv6 源码窥探(2)】懒分配策略】多看
推荐阅读
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 20190302|20190302 复盘翻盘
- 学无止境,人生还很长