【MIT 6.S081】2020, 实验记录(5),Lab: lazy allocation

目录

    • Task 1: Eliminate allocation from sbrk()
    • Task 2: Lazy allocation
    • Task 3: Lazytests and Usertests

在学习了 page fault 这一节课后,了解了操作系统是如何结合 page table 和 trap 利用 page fault 来实现一系列的神奇的功能。这个 lab 就是在 XV6 中实现 lazy allocation 机制

xv6 默认是 eager allocation,也就是用户程序一旦调用 sbrk,内核会立刻分配应用程序所需要的物理内存。这个实验就是将其修改为 lazy allocation,用户在调用 sbrk 时不会立刻分配物理内存,只是做一个记录,等到程序真正读写这个内存 page 时,才会因触发 page fault 而让内核分配一个实际的物理内存并修改到 page table 中。

Task 1: Eliminate allocation from sbrk()

这个 task 让我们删除 sbrk 的系统调用实现函数 sys_sbrk() 中分配物理内存的代码,内核只需要增大 myproc()->sz 这个值即可。

myproc()->sz 这个值记录的当前用户进程已申请的 heap 的最大地址:
sbrk

代码(kernel/sysproc.c):

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

make qemu 后执行 echo hi

task-1
这里会发生 page fault,在下面的 task 中,我们将处理发生的 page fault,并为其分配物理内存 page 且修改对应的 page table。

Task 2: Lazy allocation

这个 task 需要修改代码来处理 page fault 并为用户程序分配物理内存。

当 page fault 发生时,程序会通过 trap 机制进入 usertrap() 函数,我们可以在这里实现相关的而逻辑。SCAUSE 寄存器记录了本次 trap 发生的原因,当寄存器的值为 13 或 15 时,表示因 load 或 store 指令访问一个地址但没找到相应 PTE 而发生 page fault,所以我们需要在 usertrap() 函数中判断 SCAUSE 寄存器的值,并实现相应的 page fault 处理逻辑。

首先在 usertrap() 函数(kernel/trap.c)中添加对 page fault 的识别并调用 page fault handler 来处理:

usertrap 函数
添加并实现 page_fault_handler() 函数(代码紧跟在 usertrap 函数后面就可以):

//
// handle page fault
//
void 
page_fault_handler(struct proc * const p)
{uint64 va = r_stval();  // 触发 page fault 的虚拟地址if (p->sz <= va || va < p->trapframe->sp) {  // 如果 va 高于 sbrk 申请的地址或者低于栈顶地址p->killed = 1;} else {uint64 ka = (uint64) kalloc();if (ka == 0) {  // 如果物理内存不足p->killed = 1;} else {memset((void*) ka, 0, PGSIZE);  // 为这块地址填充 0va = PGROUNDDOWN(va);  // round the faulting virtual address down to a page boundary.// 将 va -> ka 的 mapping 添加到 user page table 中if (mappages(p->pagetable, va, PGSIZE, ka, PTE_W | PTE_X | PTE_U | PTE_R) != 0) {kfree((void*) ka);p->killed = 1;}}}
}

还存在一个问题,因为用户申请的内存并没有一定分配实际的物理内存,所以在对申请但未分配的内存做 unmap 时会产生错误,因此需要对 unmap 的代码进行修改,当想要释放一个未分配的 page 时,代码中只需要直接忽视就可以了(vm.c):

ummap 函数
完成以上修改后,make qemu 之后就可以正常运行 echo hi 了:

task2

Task 3: Lazytests and Usertests

前一个 task 实现了一个简单的 lazy allocation,执行 echo hi 是没问题了,但在更复杂的场景下,仍然有许多需要考虑的事情,本 task 要求完善 lazy allocation 并能够通过 lazytestsusertests 两个测试。

首先为了实现的方便,这里将实际分配物理内存的代码逻辑封装到 alloc_memory_page() 函数(kernel/vm.c)中:

// 分配一个实际物理内存,并映射到 va 中,将这个 mapping 添加到 page table 中
uint64
alloc_memory_page(uint64 va, pagetable_t pagetable)
{uint64 ka = (uint64) kalloc();if (ka == 0) {  // 如果物理内存不足return 0;}memset((void*) ka, 0, PGSIZE);  // 为这块地址填充 0va = PGROUNDDOWN(va);  // round the faulting virtual address down to a page boundary.if (mappages(pagetable, va, PGSIZE, ka,  PTE_W | PTE_X | PTE_R | PTE_U) != 0) {kfree((void*) ka);return 0;}return ka;
}

这个函数通过 kalloc() 来分配一个物理内存 page,并将其映射到 va 中,然后将这个 mapping 添加到 page table 中。当成功时,函数返回分配的物理内存地址,当失败时(内存不足或添加 mapping 失败),函数返回 0。

我们将这个 alloc_memory_page() 函数的声明放到 defs.h 头文件中。

有了这个 alloc_memory_page 函数,我们在上一个实验写的 page fault handler 就可以简化一下了,分配物理内存的逻辑改为调用 alloc_memory_page 即可:

//
// handle page fault
//
void 
page_fault_handler(struct proc * const p)
{uint64 va = r_stval();if (p->sz <= va || va < p->trapframe->sp) {  // 如果 va 高于 sbrk 申请的地址或者低于栈顶地址p->killed = 1;} else {if (alloc_memory_page(va, p->pagetable) == 0) {  // 当分配内存或添加 mapping 失败,就直接杀死该进程p->killed = 1;}}
}

修改 uvmummap() 函数,当无法从 page table 中找到 va 的 PTE 时或者 PTE 未映射时,直接跳过:

uvmunmap
我们还需要正确处理 fork 时父进程向子进程 copy 内存的逻辑,这里需要修改 uvmcopy() 函数,也是在页表不存在或 PTE 未映射时直接跳过:

uvmcopy
还有一种情况是,当用户程序把通过 sbrk() 申请的内存(但还未实际分配)的内存地址传递给系统调用时,kernel 可能会在 copyincopyout 这两个函数中访问这个内存地址,而 kernel 内是无法像用户程序那样走 page fault handler 来 lazy allocation 的,所以我们必须在 copyincopyout 函数内也实现“访问用户程序传来的内存地址时做 lazy allocation”的逻辑:

copyout
这里 copyout 通过 walkaddr 来将 va 借助 user page table 来翻译得到 pa,但由于我们采用了 lazy allocation 机制,所以这里可能无法找到 PTE 映射,所以,当没有找到 PTE 映射时,我们需要立刻为其分配物理内存并修改 user page table,这也是上图红方框内代码的逻辑。对于 copyin 函数,所做的修改类似:

copyin
至此,我们完成了 lazy allocation,测试如下:

运行 lazytests:
lazytests
运行 usertests:
usertests

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/450364.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[SWPUCTF 2021 新生赛]easyupload2.0

一开始我通过cobaltstrike写一个文件上传的木马它不允许上传php文件 我这边写了一句话木马通过burp拦截修改后缀为phtml然后通过蚁剑找flag

【数据结构】链表OJ面试题2(题库+解析)

1.前言 前五题在这http://t.csdnimg.cn/UeggB 休息一天&#xff0c;今天继续刷题&#xff01; 2.OJ题目训练 1. 编写代码&#xff0c;以给定值x为基准将链表分割成两部分&#xff0c;所有小于x的结点排在大于或等于x的结点之前 。链表分割_牛客题霸_牛客网 思路 既然涉及…

Acwing第 141 场周赛

A题 签到模拟即可 B题 单独考虑每一个a[i]&#xff0c;如果i要是答案需要指针移动多少次&#xff0c;然后算完&#xff0c;排个序&#xff0c;指针移动最少的就是答案。 #include <bits/stdc.h> #define int long long #define rep(i,a,b) for(int i (a); i < (…

【QT+QGIS跨平台编译】之二十二:【FontConfig+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、FontConfig介绍二、文件下载三、文件分析四、pro文件五、编译实践 一、FontConfig介绍 FontConfig 是一个用于配置和定制字体的库&#xff0c;广泛应用于基于X Window系统的操作系统中&#xff0c;尤其是在Linux和Unix-like系统中。它为应用程序提供了一种统一的…

车载测试Vector工具——基于DoIP的ECU/车辆的连接故障排除

车载测试Vector工具——基于DoIP的ECU/车辆的连接故障排除 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和…

【周总结】Programmer‘s weekend routine---First week of February

总结 工作&#xff1a; 参加项目重构方案讨论会议、个人任务计划分期以及工期安排、项目初步重构开发 日常&#xff1a;参加年会&#xff08;阳光普照奖都莫得&#xff09; 2024.2.3 阴 不冷 连着一周的雨&#xff0c;我那袜子挂两三天了还能挤出水。。离谱、莆…

MySQL全表扫描:性能杀手的隐患与优化策略

MySQL全表扫描&#xff1a;性能杀手的隐患与优化策略 MySQL数据库作为常用的关系型数据库管理系统之一&#xff0c;全表扫描问题一直困扰着开发者。本文将深入剖析MySQL全表扫描的原理、其对性能的严重影响&#xff0c;同时提供一系列优化策略&#xff0c;助您高效应对MySQL性能…

2.3作业

一&#xff0e;选择题 1、适宜采用inline定义函数情况是&#xff08;C&#xff09; A. 函数体含有循环语句 B. 函数体含有递归语句 C. 函数代码少、频繁调用 D. 函数代码多、不常调用 2、假定一个函数为A(int i4, int j0) {;}, 则执行“A (1);”语句后&#xff0c;i和j的值分别…

TQ15EG开发板教程:开发板资源介绍

时钟资源 采用时钟芯片CDCM6208提供系统时钟 PL端时钟 PS 收发器时钟 PL收发器时钟 电源 BANK500 BANK501 BANK502 BANK503(专用) 1.8V 1.8V 1.8V 1.8V PS端外设 QSPI 采用2片MT25QU256 拼接成8bit的QSPI存储系统。采用1.8V供电 SD卡 SATA接口 PS端以太网接口 D…

字符数组的学习

前言&#xff1a; 在前面我们介绍过字符型数据是以字符的ASCII码储存在存储单元中&#xff0c;一般占一个字节&#xff0c;由于 ASCII码也属于整数类型&#xff0c;因此在C99标准中把字符类型归纳为整数类型中的一种&#xff0c;由于字符数据 的应用比较广泛&#xff0c;尤其…

演讲回顾:如何为大规模研发团队加速CI构建,实现高效流水线

近日&#xff0c;龙智联合Atlassian举办的DevSecOps研讨会年终专场”趋势展望与实战探讨&#xff1a;如何打好DevOps基础、赋能创新”在上海圆满落幕。龙智Atlassian技术与顾问咨询团队&#xff0c;以及清晖、JamaSoftware、CloudBees等生态伙伴的嘉宾发表了主题演讲&#xff0…

【高阶数据结构】红黑树

文章目录 前言什么是红黑树红黑树的性质红黑树结点的定义红黑树的插入情况一情况二情况三插入代码总结 验证是否为红黑树红黑树的删除 前言 前面我们学习了 AVL 树——高度平衡的二叉搜索树&#xff0c;AVL 树保证了结点的左右子树的高度差的绝对值不超过 1&#xff0c;也就是…