MIT 6.S081 Lab5 Lazy Allocation

参考别人博客写的,差不多对着抄的,如侵权则删....

1.Eliminate allocation from sbrk() 

sys_sbrk里面删除 growproc代码

uint64
sys_sbrk(void)
{
  int addr;
  int n;

  if(argint(0, &n) < 0)
    return -1;
  addr = myproc()->sz;
  myproc()->sz += n; //记得添加这一行,不然会报错
  //if(growproc(n) < 0)
  //  return -1;
  return addr;
}

2. Lazy allocation (moderate)  

2.1 hints

您可以通过查看 usertrap() 中的 r_scause() 是 13 还是 15 来检查错误是否是页面错误。
r_stval() 返回 RISC-V stval 寄存器,其中包含导致页面错误的虚拟地址。
从 vm.c 中的 uvmalloc() 窃取代码,这就是 sbrk() 调用的内容(通过growproc())。 您需要调用 kalloc() 和 mappages()。
使用 PGROUNDDOWN(va) 将出错的虚拟地址向下舍入到页面边界。
uvmunmap() 会恐慌; 如果某些页面未映射,请将其修改为不恐慌。
如果内核崩溃,请在 kernel/kernel.asm 中查找 sepc
使用 pgtbl 实验室的 vmprint 函数打印页表的内容。
如果您看到错误“incomplete type proc”,请包含“spinlock.h”,然后包含“proc.h”。

2.2 实验流程

1. 在vm.c文件添加lazyalloc

uint64 lazyalloc(struct proc * p, uint64 va){

  if(va >= p->sz || va < PGROUNDUP(p->trapframe->sp)){

    return 0;
  }
  char * mem;
  uint64 a = PGROUNDDOWN(va);
  mem = kalloc();
  if(mem == 0){

    return 0;
  }
  memset(mem, 0, PGSIZE);
    if(mappages(p->pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){

      kfree(mem);
      return 0;
    }

  return (uint64)mem;
}

2. 在usertrap里面添加页处理错误

  } else if((which_dev = devintr()) != 0){
    // ok
  } else if(r_scause() == 13 || r_scause() == 15) {
        if (lazyalloc(myproc(), r_stval()) <= 0) {
     
            p->killed = 1;
        }

  } else {

1.注释掉uvmnmap的panic

for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
    if((pte = walk(pagetable, a, 0)) == 0)
      panic("uvmunmap: walk");
    if((*pte & PTE_V) == 0)
      //panic("uvmunmap: not mapped");
        continue;

这里为啥要注释掉panic呢,我的理解是,因为是懒分配,所以有一些虚拟页表中的页,实际上并没有分配物理地址的,这个时候PTE_V为0,那么在uvmunmap取消映射的时候,就不该panic,而是跳过。

2.3 PTE 是什么

 PTE是Page Table Entry的简称,翻译过来就是页表项,结构如图所示:

3. Lazytests and Usertests (moderate)

3.1 hints

处理负 sbrk() 参数。
如果进程在比 sbrk() 分配的任何内存地址高的虚拟内存地址上出现页面错误,则终止该进程。
正确处理 fork() 中的父对子内存复制。
处理进程将有效地址从 sbrk() 传递给系统调用(例如读取或写入)但尚未分配该地址的内存的情况。
正确处理内存不足:如果 kalloc() 在页面错误处理程序中失败,则终止当前进程。
处理用户堆栈下方无效页面上的错误。

3.1修改sbrk代码

uint64
sys_sbrk(void)
{
  int addr;
  int n;
  struct proc *p = myproc();

  if(argint(0, &n) < 0)
    return -1;
  addr = p->sz;
  p->sz += n;
  //if(growproc(n) < 0)
  //  return -1;
  if(n < 0) {
    uvmdealloc(p->pagetable, addr, p->sz); //删除页
  }
  return addr;
}

3.2 修改walkaddr代码,实现懒加载

uint64
walkaddr(pagetable_t pagetable, uint64 va)
{
  pte_t *pte;
  uint64 pa;

  if(va >= MAXVA)
    return 0;

  pte = walk(pagetable, va, 0);
  if(pte == 0)
    goto lzac;
  if((*pte & PTE_V) == 0)
    goto lzac;
  if((*pte & PTE_U) == 0)
    goto lzac;
  pa = PTE2PA(*pte);
  if (0) { //注意这一行必须要有,因为有些情况是不需要lazyalloc的,不然报错init exiting
    lzac:
    if((pa = lazyalloc(myproc(), va)) <= 0){
      pa = 0;
    }
  }
  return pa;
}

其实我的总结就是,在需要的时候进行页面加载,并且消除掉因为缺页而导致的panic,缺页的情况,可能是用户write操作copyin,导致页错误

3.3 注释掉不必要的panic

 所有case都过了

总结

不仔细读题,导致自己死得很难看。。。。 myproc()->sz += n; 这一行忘了加,所以我的教训就是,自己要做的事情,一定要弄得十分清楚,觉得奇怪的地方多问为什么

对事物的背景、条件、提示等,真的要在意

画图能够加深印象,记得更牢,理解更透彻

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值