Mit6.s081-lab5

本实验主要关于懒分配的知识。

前置:

一个广泛使用的特性叫做惰性分配——lazy allocation。它包括两部分内容:首先,当应用程序调用sbrk时,内核增加地址空间,但在页表中将新地址标记为无效。其次,对于包含于其中的地址的页面错误,内核分配物理内存并将其映射到页表中。由于应用程序通常要求比他们需要的更多的内存,惰性分配可以称得上一次胜利: 内核仅在应用程序实际使用它时才分配内存。像COW fork一样,内核可以对应用程序透明地实现此功能。

Eliminate allocation from sbrk()

应该删除对growproc()的调用,但是需要增加进程的大小。

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

  if(argint(0, &n) < 0)
    return -1;

  addr = myproc()->sz;
  // lazy allocation
  myproc()->sz += n;

  return addr;
}

Lazy allocation

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

usertrap

else if(r_scause()==13||r_scause()==15)
   {//页面错误
       uint64 va = r_stval();//获取异常地址
       char *mem;
       //对齐到页边界
       va=PGROUNDDOWN(va);

       if((mem = kalloc())==0)
       {
        //如果分配失败
        panic("cannot allocate for lazy alloc\n");
        exit(-1);
       }
       // 将物理页映射到进程的页表中,赋予写、执行、读和用户权限
       if (mappages(p->pagetable, va, PGSIZE, (uint64)mem, 
       PTE_W | PTE_X | PTE_R | PTE_U) != 0) 
       {
         // 如果映射失败,释放分配的内存,打印错误信息并退出当前进程
         kfree(mem);
         panic("cannot map for lazy alloc\n");
         exit(-1);
       }
   }
   else {

修改uvmunmap()(kernel/vm.c),之所以修改这部分代码是因为lazy allocation中首先并未实际分配内存,所以当解除映射关系的时候对于这部分内存要略过,而不是使系统崩溃。

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

Lazytests and Usertests

处理sbrk()参数为负数的情况,参考之前sbrk()调用的growproc()程序,如果为负数,就调用uvmdealloc()函数,但需要限制缩减后的内存空间不能小于0

if (n < 0) {
    // 如果需要减少内存大小 (n 为负值)
    
    // 检查减少后的内存大小是否为负数
    if ((myproc()->sz + n) < 0) {
        // 如果减少后的内存大小小于 0,返回错误
        return -1;
    } else {
        // 否则,尝试释放内存
        // `addr` 是当前进程内存的末尾地址
        // `addr + n` 是减少后的新的内存末尾地址
        if (uvmdealloc(myproc()->pagetable, addr, addr + n) != (addr + n)) {
            // 如果内存释放失败,返回错误
            return -1;
        }
    }
}

fork()中将父进程的内存复制给子进程的过程中用到了uvmcopyuvmcopy原本在发现缺失相应的PTE等情况下会panic,这里也要continue掉。在kernel/vm.c的uvmcopy中.

if((pte = walk(old, i, 0)) == 0)
    continue;
    // panic("uvmcopy: pte should exist");
    if((*pte & PTE_V) == 0)
    continue;
    // panic("uvmcopy: page not present");

当造成的page fault在进程的user stack以下(栈底)或者在p->sz以上(堆顶)时,kill这个进程。在kernel/trap.c的usertrap中增加以下判断条件

if ((va < p->sz) && (va > PGROUNDDOWN(p->trapframe->sp)))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值