MIT6.S081 LAB5实验记录

这个实验主要是让我们实现内存的延迟分配用户空间堆内存,当我们需要分配堆空间时候,不是立即分配内存给它,而是记录分配了哪些用户地址,并在用户页表中将这些地址标记为无效。当进程第一次尝试使用延迟分配中给定的页面时,CPU生成一个页面错误,内核通过分配物理内存、置零并添加映射来处理该错误。

Eliminate allocation from sbrk

你的首项任务是删除sbrk(n)系统调用中的页面分配代码(位于sysproc.c中的函数sys_sbrk())。sbrk(n)系统调用将进程的内存大小增加n个字节,然后返回新分配区域的开始部分(即旧的大小)。新的sbrk(n)应该只将进程的大小(myproc()->sz)增加n

//sysproc.c
uint64
sys_sbrk(void)
{
  int addr;
  int n;

  if(argint(0, &n) < 0)
    return -1;
  addr = myproc()->sz;
  if(n > 0)   myproc()->sz += n;
  if(myproc()->sz + n >= 0 && n < 0){
    myproc()->sz = uvmdealloc(myproc()->pagetable, myproc()->sz, myproc()->sz + n);//n小于零则删除多余的内存。
  }
  if(myproc()->sz + n < 0 && n < 0) return -1;

  //if(growproc(n) < 0)
    //return -1;
  return addr;
}

我们将sbrk()中分配内存给删除,在sbrk中我们只将要分配的内存进行标记,并不实际分配物理内存。

Lazy allocation

修改trap.c中的代码以响应来自用户空间的页面错误,方法是新分配一个物理页面并映射到发生错误的地址,然后返回到用户空间,让进程继续执行

//trap.c
else if(r_scause() == 13 || r_scause() == 15){ //当出现页面错误中断时
    uint64 addr;
    char *mem;
    addr = r_stval();//获取当前出错的地址
    if(addr >= p->sz)  p->killed = 1;//如果大于已分配的内存,则杀死进程
    else if(addr < p->trapframe->sp) p->killed = 1;//如果地址在栈指针的下面,则杀死内存
    else {
    addr = PGROUNDDOWN(addr);
    mem = kalloc();
    if(mem == 0) {
      p->killed = 1;
    } else {
    memset(mem, 0, PGSIZE);
    if(mappages(p->pagetable, addr, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U|PTE_V) != 0) {
      kfree(mem);
      p->killed = 1;
      }
    }
    }
  }

Lazytests and Usertests

进行一些细节的修改

//vm.c
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;
      //panic("uvmunmap: walk");
    if((*pte & PTE_V) == 0)
      continue;
      //panic("uvmunmap: not mapped");
    if(PTE_FLAGS(*pte) == PTE_V)
      panic("uvmunmap: not a leaf");
    if(do_free){
      uint64 pa = PTE2PA(*pte);
      kfree((void*)pa);
    }
    *pte = 0;
  }
} //注释掉panic,当发现PTE无效时,跳过。
//在uvmcopy中也进行相同的操作。
//syscall.c
//当我们在内核空间时,不会触发页错误,但是我们需要调用地址时需要使用argaddr函数,所以当我们调用argaddr函数时,如果发现用户地址被标记但未被分配,我们为此地址分配页面。
int
argaddr(int n, uint64 *ip)
{
  char *mem;
  *ip = argraw(n);
  struct proc *p = myproc();

  if(walkaddr(p->pagetable, *ip) == 0) {
    if(*ip >= myproc()->sz) return -1;
    if(*ip < PGROUNDUP(p->trapframe->sp)) return -1;
    mem = kalloc();
    if(mem == 0) return -1;
    memset(mem, 0, PGSIZE);
    if(mappages(myproc()->pagetable, PGROUNDDOWN(*ip), PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0) {
      kfree(mem);
      return -1;
    }
  }

  return 0;
}

当我们分配内存时,有很多内存也许短时间内不会用到,而马上分配实际内存会浪费过多的时间,我们可以到需要时才分配实际内存。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值