2020 MIT6.S081 lab5:lazy page allocation

2020 MIT6.S081 lab5:lazy page allocation

简介

(前几次实验忘做笔记了,懒得写了(逃…))
本次lab需要完成lazy page allocation
在os中,当我们每次使用sbrk()函数增加堆空间时,要为每个page都重新初始化并分配虚拟内存。但通常情况我们用的内存小于所花费的空间,故进行lazy allocation策略,即是先让明面上的空间增加,但并不分配内存,在调用时访问虚拟内存发现page fault的时候则调用重新分配空间。

Eliminate allocation from sbrk

pcb进程图
任务介绍:
改写sbrk()函数,返回的依然是原指针,但增加时不在此处分配内存。
在proc.h中的 s z sz sz即为图中pagesize开始指向栈顶,增加内存后指针向上移动,栈为向下分配。
则注释掉原来的 g r o w p r o c growproc growproc函数,直接修改 m y p r o c ( ) − s z myproc()-sz myproc()sz即可
下面展示一些 内联代码片

// An highlighted block
uint64
sys_sbrk(void)
{
  int addr;
  int n;

  if(argint(0, &n) < 0)
    return -1;
  addr = myproc()->sz;
  myproc()->sz = myproc()->sz+n;
  //if(growproc(n) < 0)
    //return -1;
  return addr;
}

Lazy allocation

修改usertrap中的代码,进入page fault后,对产生页面中断的页面进行页面分配

// An highlighted block
void usertrap(void)
{
  int which_dev = 0;

  if ((r_sstatus() & SSTATUS_SPP) != 0)
    panic("usertrap: not from user mode");

  // send interrupts and exceptions to kerneltrap(),
  // since we're now in the kernel.
  w_stvec((uint64)kernelvec);

  struct proc *p = myproc();

  // save user program counter.
  p->trapframe->epc = r_sepc();

  if (r_scause() == 8)
  {
    // system call

    if (p->killed)
      exit(-1);

    // sepc points to the ecall instruction,
    // but we want to return to the next instruction.
    p->trapframe->epc += 4;

    // an interrupt will change sstatus &c registers,
    // so don't enable until done with those registers.
    intr_on();
    syscall();
  }
  else if ((which_dev = devintr()) != 0)
  {
    // ok
  }
  else if (r_scause() == 13 || r_scause() == 15)
  {
    uint64 va = r_stval();//产生中断的地址
    if (va >= p->sz || va < PGROUNDDOWN(p->trapframe->sp))
    {//判断va==p->sz的时候地址不可用,va==栈顶时可用
      p->killed = 1;
    }
    else
    {
      uint64 bottom = PGROUNDDOWN(va);
      //printf("%d\n", r_scause());
      //printf("page fault %p\n", va);
      char *mem = kalloc();
      if (mem == 0)
      {
        p->killed = 1;
      }
      else
      {
        memset(mem, 0, PGSIZE);
        if (mappages(p->pagetable, bottom, PGSIZE, (uint64)mem, PTE_X|PTE_W | PTE_U | PTE_R) != 0)
        {
          kfree(mem);
          p->killed = 1;
        }
      }
    }
  }
  else
  {
    printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
    printf("            sepc=%p stval=%p\n", r_sepc(), r_stval());
    p->killed = 1;
  }

  if (p->killed)
    exit(-1);

  // give up the CPU if this is a timer interrupt.
  if (which_dev == 2)
    yield();

  usertrapret();
}

这时我们再运行代码,依然会报错,因为在进程结束时,它释放内存的时候对栈0-sz的空间都进行了释放,但有些页是没有分配的。故修改uvmunmap函数

// An highlighted block
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)
      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;
  }
}

但这还有改进的空间,目前只处理了sbrk增加的情况,减小同样需要考虑,空间减小时,我们释放内存。

// An highlighted block
uint64
sys_sbrk(void)
{
  int addr;
  int n;

  if(argint(0, &n) < 0)
    return -1;
  addr = myproc()->sz;
  if(n<0){
    if((myproc()->sz+n)<0){
      uvmunmap(myproc()->pagetable,0,PGROUNDUP(addr)/PGSIZE,1);
      return -1;
    }
    else{
      if(uvmdealloc(myproc()->pagetable,addr,addr+n)!=addr+n){
        return -1;
      }
    }
  }
  myproc()->sz = myproc()->sz+n;
  //if(growproc(n) < 0)
    //return -1;
  return addr;
}

fork时会调用uvmcopy函数,此函数中也有类似前者对未分配页的判定,修改。

// An highlighted block
    if ((pte = walk(old, i, 0)) == 0)
      continue;
    if ((*pte & PTE_V) == 0)
      continue;

考虑在调用walkaddr时也可能触发页面未分配(此处也是解决read和write问题的方法)。

// An highlighted block
uint64
walkaddr(pagetable_t pagetable, uint64 va)
{
  pte_t *pte;
  uint64 pa;

  if (va >= MAXVA)
    return 0;
  struct proc *p = myproc();
  pte = walk(pagetable, va, 0);
  if (pte == 0 || (*pte & PTE_V) == 0){
    if (va >= p->sz || va < PGROUNDDOWN(p->trapframe->sp)){
      return 0;
    }
    char *mem=kalloc();
    uint64 pa0=(uint64)mem;
    memset(mem,0,PGSIZE);
    mappages(pagetable,va,PGSIZE,pa0,PTE_X|PTE_W | PTE_U | PTE_R);
    return (uint64)mem;
  }
  if ((*pte & PTE_U) == 0)
    return 0;
  pa = PTE2PA(*pte);
  return pa;
}

o v e r ! over! over!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值