xv6 lazy allocation

Eliminate allocation from sbrk()

这部分很简单

直接修改函数即可

但要考虑到传入的n是负数的情况

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

  if(argint(0, &n) < 0)
    return -1;
  struct proc* p=myproc();

  addr = p->sz;
  if(addr+n>MAXVA || addr+n<0)
    return addr;
  p->sz=addr+n;
  if(n<0)
  {
    uvmdealloc(p->pagetable, addr, p->sz);
  }
  // if(growproc(n) < 0)
  //   return -1;
  return addr;
}

处理负数情况不能直接调用growproc() 会改变p->sz

Lazy allocation

这部分的 hint其实只是给出遇到问题后去怎么解决 总体思路就是实现lazy allocation

我建议就是想到一个得修改的地方 写上 然后调试去找新的错误

lab的最后一部分

Lazytests and Usertests

其实就是要你一步步实现完善的

所以第二个和第三个要一起做

第二个hints是叫你遇到故障怎么班

第三个hints就是你要handle的地方 也就是坑

下面贴出要修改的函数

这是usertrap的部分

} else if (r_scause() == 13 || r_scause() == 15)
  {
    uint64 va = r_stval();
    if(va > p->sz || va <=PGROUNDDOWN( p->trapframe->sp))
    {
      p->killed=1;
    }
    //printf("page fault: %p\n",va);
    else{
    uint64 ka = (uint64)kalloc();
    if(ka == 0)
    {
      p->killed=1;
    } else{
      memset((void*)ka,0,PGSIZE);
      va=PGROUNDDOWN(va);
      if(mappages(p->pagetable,va,PGSIZE,ka,PTE_W|PTE_U|PTE_R)!=0)
      {
        kfree((void*)ka);
        p->killed=1;
      }
    }}
  }

 注意 va 边界条件 然后每个可以会返回错误值的函数一定要判断

void
uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
{
  uint64 a;
  pte_t *pte;

  if((va % PGSIZE) != 0)
    panic("uvmunmap: not aligned");

  for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
    if((pte = walk(pagetable, a, 0)) == 0)
      {
        //vmprint(pagetable);
        // printf("%p\n",a);
        continue;
        }
    if((*pte & PTE_V) == 0)
      continue;
    if(PTE_FLAGS(*pte) == PTE_V)
      panic("uvmunmap: not a leaf");
    if(do_free){
      uint64 pa = PTE2PA(*pte);
      kfree((void*)pa);
    }
    *pte = 0;
  }
}

这里是是把pte为0的情况 和pte无效的情况变成continue

以为如果不是lazy allocation的话 根本不会去unmap这样的pte

只有lazy allocation 才能去unmap没有分配空间而导致pte无效的情况

int
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
{
  pte_t *pte;
  uint64 pa, i;
  uint flags;
  char *mem;

  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;
    pa = PTE2PA(*pte);
    flags = PTE_FLAGS(*pte);
    if((mem = kalloc()) == 0)
      goto err;
    memmove(mem, (char*)pa, PGSIZE);
    if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
      kfree(mem);
      goto err;
    }
  }
  return 0;

 err:
  uvmunmap(new, 0, i / PGSIZE, 1);
  return -1;
}

修改原因同上 主要是处理fork()

int
mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm)
{
  uint64 a, last;
  pte_t *pte;

  a = PGROUNDDOWN(va);
  last = PGROUNDDOWN(va + size - 1);
  for(;;){
    if((pte = walk(pagetable, a, 1)) == 0)
      return -1;
    if(*pte & PTE_V)
      // panic("remap");
      continue;
    *pte = PA2PTE(pa) | perm | PTE_V;
    if(a == last)
      break;
    a += PGSIZE;
    pa += PGSIZE;
  }
  return 0;
}

这是跑测试用例的时候发现的 从别的函数中调用的mappages()

void
freewalk(pagetable_t pagetable)
{
  // there are 2^9 = 512 PTEs in a page table.
  for(int i = 0; i < 512; i++){
    pte_t pte = pagetable[i];
    if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){
      // this PTE points to a lower-level page table.
      uint64 child = PTE2PA(pte);
      freewalk((pagetable_t)child);
      pagetable[i] = 0;
    } else if(pte & PTE_V){
      // panic("freewalk: leaf");
      continue;
    }
  }
  kfree((void*)pagetable);
}

同理

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||(*pte & PTE_V) == 0)
    {
    
      
    struct proc *p=myproc();
    if (va >= p->sz || va < PGROUNDUP(p->trapframe->sp)) return 0;
    uint64 ka = (uint64)kalloc();
    if(ka == 0)
    {
      return 0;
      //p->killed=1;
    } else{
      memset((void*)ka,0,PGSIZE);
      //va=PGROUNDDOWN(va);
      if(mappages(p->pagetable,va,PGSIZE,ka,PTE_W|PTE_U|PTE_R|PTE_X)!=0)
      {
        kfree((void*)ka);
        p->killed=1;
      }
    }
    return PTE2PA(*walk(pagetable, va, 0));
    }
  if((*pte & PTE_U) == 0)
    return 0;
  pa = PTE2PA(*pte);
  return pa;
}

这是write 和 read 系统调用的底层函数

需要重新写分配内存空间的代码

因为不会进入到trap中处理

注意我们这里的虚拟地址是具体的 一定不要舍入

这部分代码还是需要思考的

下面是做lab的思考和调试手段

跟着测试用例来去修改函数确实很省时间 总有思考不到的地方会panic

没有用到hints说的 vmprint

kernel 也没有crash过

主要就是调内核和用户代码

usertests代码太长 可以把没通过的函数单独放.c文件来调

其实可以用backtrace 但我没用

总体来说用例还是很严格的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值