首先先切换到lazy分支
git checkout lazy
make clean
Xv6应用程序使用sbrk()
系统调用向内核请求堆内存。sbrk()
分配物理内存并将其映射到进程的虚拟地址空间。内核为一个大请求分配和映射内存可能需要很长时间。为了提高效率,故采用懒分配的策略
Eliminate allocation from sbrk()
删除sbrk(n)
系统调用中的页面分配代码(kernel/sysproc.c)
Lazy allocation
1.修改kernel/trap.c里面的usertrap()函数,根据r_scause()判断是否为页面错误,(p->sz代表进程的地址上限)然后分配物理内存并添加映射
2.修改kernel/vm.c中的uvmunmap()函数,lazy allacation中没有实际分配内存,那么解除映射关系的时候这部分内存也要略过
第一个continue而言,主要解决的问题是一二级页表中存在Lazy Alloction的pte还未建立映射关系,所以walk函数会返回0
对于第二个continue而言,解决的是第三级叶子层页表中,某个pte还未建立映射关系,虽然walk函数返回值不为0,但是该pte是无效的
Lazytests and Usertests
1.kernel/sysproc.c中处理sbrk()参数为负数的情况,两种情况:sz+n >0 以及sz + n < 0。后面这种情况直接return - 1即可
前面那种则参考growproc()函数,调用uvmdealloc()函数缩减内存
2.处理fork拷贝(kernel/proc.c)
fork调用了uvmcopy(kernel/vm.c)进行内存拷贝,但现在进行了懒分配所以就不需要了,更改uvmcopy函数
3.还需要注意懒分配带来的影响,系统调用处理会陷入内核,scause寄存器存储的值是8,如果此时传入的地址还没有实际分配,并且此时也没有途径走到页面错误(scause = 13或者15的分支)那么syscall执行就会失败
-
系统调用流程:
-
陷入内核–>
usertrap
中r_scause()==8
的分支–>syscall()
–>回到用户空间
-
-
页面错误流程:
-
陷入内核–>
usertrap
中r_scause()==13||r_scause()==15
的分支–>分配内存–>回到用户空间
-
所以使用系统调用的时候必须要知道何时会使用这些地址避免出现错误,事实上,将地址传入系统调用后,会通过argaddr
函数(kernel/syscall.c)从寄存器中读取,因此在这里添加物理内存分配的代码
测试