MIT 6.S081 实验5 笔记与心得

Lab 5:Lazy

前期准备

O/S可以利用页表硬件玩的很多花样之一是懒惰地分配用户空间的堆内存。Xv6应用程序使用sbrk()系统调用向内核索取堆内存。在我们给你的内核中,sbrk()分配物理内存并将其映射到进程的虚拟地址空间。内核为一个大的请求分配和映射内存可能需要很长的时间。例如,考虑到一千兆字节由262,144个4096字节的页面组成;这是一个巨大的分配数量,即使每个分配都很便宜。此外,一些程序分配的内存比它们实际使用的要多(例如,为了实现稀疏数组),或者在使用之前提前分配内存。为了让sbrk()在这些情况下更快地完成,复杂的内核会懒散地分配用户内存。也就是说,sbrk()并不分配物理内存,而只是记住哪些用户地址被分配,并在用户页表中把这些地址标记为无效。当进程第一次尝试使用任何指定的懒惰分配的内存页时,CPU会产生一个页面故障,内核通过分配物理内存、清零和映射来处理。你将在本实验中为xv6添加这个懒惰分配功能。

Before you start coding, read Chapter 4 (in particular 4.6) of the xv6 book, and related files you are likely to modify:

  • kernel/trap.c
  • kernel/vm.c
  • kernel/sysproc.c

Eliminate allocation from sbrk() (easy)

题目翻译

你的第一个任务是从sbrk(n)系统调用实现中删除页面分配,也就是sysproc.c中的函数sys_sbrk()。sbrk(n)系统调用将进程的内存大小增加n字节,然后返回新分配区域的开始(即旧大小)。你的新sbrk(n)应该只是将进程的大小(myproc()->sz)增加n,并返回旧的大小。它不应该分配内存 – 所以你应该删除对growproc()的调用(但你仍然需要增加进程的大小!)。

试着猜测一下这个修改的结果是什么:什么会被破坏?

进行这个修改,启动xv6,在shell中输入echo hi。你应该看到像这样的东西。

init: starting sh
$ echo hi
usertrap(): unexpected scause 0x000000000000000f pid=3
            sepc=0x0000000000001258 stval=0x0000000000004008
va=0x0000000000004000 pte=0x0000000000000000
panic: uvmunmap: not mapped

"usertrap(): … "消息来自于Trap.c中的用户陷阱处理程序;它捕获了一个它不知道如何处理的异常。请确保你理解为什么会发生这种页面故障。stval=0x0…04008 "表明导致页面故障的虚拟地址是0x4008。

题目答案

这一题比较简单,只需要删除kernel/sysproc.c中sys_sbrk()里面的growproc()函数即可,然后其他稍作改变。

uint64
sys_sbrk(void){
   
	int addr;
	int n;
	struct proc *p = myproc();
    if(argint(0, &n) < 0)
    return -1;
    addr = p->sz;
    p->sz+=n;
    return addr;
}

Lazy allocation (moderate)

题目翻译

修改 trap.c 中的代码,以响应来自用户空间的页面故障,在故障地址处映射一个新分配的物理内存页面,然后返回用户空间,让进程继续执行。你应该在产生信息"usertrap():…"的printf调用之前添加你的代码。修改你需要的其他xv6内核代码,以使echo hi工作。

一些提示:

  • 你可以通过查看usertrap()中的r_scause()是否为13或15来检查一个故障是否是页故障。
  • r_stval()返回RISC-V的stval寄存器,它包含了引起页面故障的虚拟地址。
  • 从vm.c中的uvmalloc()偷取代码,这就是sbrk()调用的代码(通过growproc())。你需要调用 kalloc() 和 mappages()。
  • 使用PGROUNDDOWN(va)将出错的虚拟地址四舍五入到一个页面边界。
  • uvmunmap()会发生恐慌;修改它,使其在某些页面没有被映射时不发生恐慌。
  • 如果内核崩溃了,在kernel/kernel.asm中查找sepc
  • 使用你在pgtbl实验室的vmprint函数来打印页表的内容
  • 如果你看到错误 “不完整的proc类型”,包括 "spinlock.h "然后 “proc.h”。

如果一切顺利,你的懒惰分配代码应该导致echo hi工作。你应该至少得到一个页面故障(从而得到懒惰分配),也许是两个。

题目答案

这里和第三问放在一起进行解答,见第三问解答

Lazytests and Usertests (moderate)

题目翻译

我们为你提供了lazytests,一个xv6的用户程序,测试一些可能给你的懒惰内存分配器带来压力的特殊情况。修改你的内核代码,使所有的lazytests和usertests都能通过。

一些提示:

  • 处理负的sbrk()参数。
  • 如果一个进程在一个比sbrk()分配的虚拟内存地址更高的地方发生页面故障,则杀死它。
  • 正确处理fork()中父子间的内存拷贝。
  • 处理这样的情况:进程从 sbrk() 传递一个有效的地址给系统调用,如 read 或 write,但该地址的内存还没有被分配。
  • 正确处理内存不足的情况:如果kalloc()在页面故障处理程序中失败,则杀死当前进程。
  • 处理用户堆栈下面的无效页面的故障。

如果你的内核通过了lazytests和usertests,你的解决方案是可以接受的。

$  lazytests
lazytests starting
running test lazy alloc
test lazy alloc: OK
running test lazy unmap...
usertrap(): ...
test lazy unmap: OK
running test out of memory
usertrap(): ...
test out of memory: OK
ALL TESTS PASSED
$ usertests
...
ALL TESTS PASSED
$
题目答案

首先对于输入的增加或者缩减的内存数目进行处理,在sysproc.c中进行处理,这里有几个需要注意的,对于n正负的处理,这里正数的话,直接进行懒分配即可,对于负数,可以观察growproc()对于负数的处理,这里模仿一下

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值