关于操作系统:xv6-源码窥探2懒分配策略

4次阅读

共计 2323 个字符,预计需要花费 6 分钟才能阅读完成。

前言

  • 本篇是对于 MIT 6.S081-2020-Lab5 的实现;
  • 如果内容上发现有什么问题请不要悭吝您的键盘。

Lazy allocation && Lazytests and Usertests

这两个练习的内容是紧耦合的,所以就写一块了。

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){...}

接着不要让 uvmcopyuvmunmap 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.

起初我不太了解为什么要特地关照 read 和 write,难道它们看到缺页不会产生 page-fault 异样吗?

所以就头铁间接跑 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;
}

后记

多看

正文完
 0