程序锅

  • 首页
  • 分类
  • 标签
  • 归档
  • 关于

  • 搜索
基础知识 Etcd LeetCode 计算机体系结构 Kubernetes Containerd Docker 容器 云原生 Serverless 项目开发维护 ELF 深入理解程序 Tmux Vim Linux Kernel Linux numpy matplotlib 机器学习 MQTT 网络基础 Thrift RPC OS 操作系统 Clang 研途 数据结构和算法 Java 编程语言 Golang Python 个人网站搭建 Nginx 计算机通用技术 Git

MIT 6.828 课程 | HW4-lazy page allocation

发表于 2019-11-25 | 分类于 MIT6.828 | 0 | 阅读次数 3023

xv6应用程序使用sbrk()system call来向kernel 请求heap memory。在kernel中已经实现了,sbrk()分配物理内存并且映射它到进程的虚拟地址。有些程序分配了内存,但不使用他们,比如在实现大型稀疏矩阵的时候。复杂的kernel延迟分配每一页的内存直到应用程序尝试使用这个页,这是由页面错误发出的信号。在这个练习中,我们要添加这种延迟分配的特点到xv6上。

Part One: Eliminate allocation from sbrk()

这个任务主要是从sbrksystem call的实现中把页分配给删掉,这个实现在sysproc.c中的sys_sbrk()中。sbrk(n)system call让进程的内存增长n个字节,然后返回新分配区域的开始地方。你现在新的sbrk(n)不应该分配内存,所以你可以删掉growproc()的调用,但是你仍然需要增加进程的大小!!

下面按照实验要求,将sys_sbrk()中分配内存的代码删除掉,但是进程的大小仍然要增加,如下

int
sys_sbrk(void)
{
  int addr, newsz;
  int n;

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

重新make(记得先make clean),然后make qemu-nox,等待shell提示输入的符号出来,之后输入echo hi,如下图所示:

这是因为没有实际分配给他们,而只是将大小增加,这样在真正执行的时候会出错,而这个出错的类型是T_PGFLT。而在trap.c中的trap函数中,没有对T_PGFLT这种情况进行处理,所以就提示出错了。

//PAGEBREAK: 13
  default:
    if(myproc() == 0 || (tf->cs&3) == 0){
      // In kernel, it must be our mistake.
      cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n",
              tf->trapno, cpuid(), tf->eip, rcr2());
      panic("trap");
    }
    // In user space, assume process misbehaved.
    cprintf("pid %d %s: trap %d err %d on cpu %d "
            "eip 0x%x addr 0x%x--kill proc\n",
            myproc()->pid, myproc()->name, tf->trapno,
            tf->err, cpuid(), tf->eip, rcr2());
    myproc()->killed = 1;

Part Two: Lazy allocation

上面既然针对T_PGFLT的情况没有进行处理,那么我们下面修改trap.c中的代码,让它可以对来自用户空间的page fault有所回应,主要通过将一个新分配的物理内存页映射到错误的地址上,然后返回用户空间继续执行。

从cprintf函数结合错误的提示,我们可以知道rcr2()为出错位置的虚拟地址。根据提示以及参考vm.c中的allocuvm()代码之后,我们可以知道当出现T_PGFLT的情况之后,我们应该处理的是分配一块物理页,然后把出错的虚拟地址映射过去。根据上述步骤,在trap.c的trap()函数中添加一个case情况,如下所示:

 // modify in hw4
case T_PGFLT:
    a = PGROUNDDOWN(rcr2());
    mem = kalloc();
    if(mem == 0){
        cprintf("trap out of memory\n");
        break;
    }
    memset(mem, 0 ,PGSIZE);
    if(mappages(myproc()->pgdir, (char*)a, PGSIZE, V2P(mem), PTE_W|PTE_U)<0){
        cprintf("trap out of memory (2)\n");
        kfree(mem);
    }
    break;

需要注意的是,要想使用mappages函数,需要将vm.c中mappages实现前面的staic关键字去掉,并且需要在trap.c中声明。vm.c中修改如下:

int
mappages(pde_t *pgdir, void *va, uint size, uint pa, int perm)
{
    ......
}

在trap.c中添加声明

// modify in hw4                                                                                 
int mappages(pde_t *pgdir, void *va, uint size, uint pa, int perm);

最后重新make之后,再次运行echo hi,效果如下:

卷死我
dawnguo 微信支付

微信支付

dawnguo 支付宝

支付宝

  • 本文作者: dawnguo
  • 本文链接: /archives/52
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# 操作系统 # OS
RPC | RPC 概念及 Thrift 简介
深入理解程序 | 静态链接的过程
  • 文章目录
  • 站点概览
dawnguo

dawnguo

215 日志
24 分类
37 标签
RSS
Creative Commons
© 2018 — 2025 程序锅
0%