MIT6.S081Lab5:xv6 lazy page allocation

Eliminate allocation from sbrk()

这个相当简单,在sys_sbrk中对growproc的调用注释掉就行,然后把sz加上n。这样应该分配的页面没有分配,同时也没有映射到页表,所以使用这些分配的页面的时候会报错panic: uvmunmap: not mapped

sys_sbrk如下:

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

运行echo hi结果如下

$ echo hi
usertrap(): unexpected scause 0x000000000000000f pid=3sepc=0x00000000000012ac stval=0x0000000000004008
panic: uvmunmap: not mapped

Lazy allocation

这个实验也还是比较简单,尤其是课程上已经有一些展示了,按照提示所说,在usertrap的最后一个else前加上处理页面错误的语句,分配一个新页面,置零,映射到页表上,然后重新执行指令,重新执行指令不需要做什么,因为此时p->trapframe->epc存储的就是引发错误的指令。不过这个实验好像没有考虑sbrk减少堆空间的情况。

usertrap新增如下

else if (r_scause() == 13 || r_scause() == 15) {uint64 va = r_stval();uint64 begin = PGROUNDDOWN(va);pagetable_t pagetable = p->pagetable;char *mem = kalloc();if(mem == 0){kfree(mem);exit(-1);}memset(mem, 0, PGSIZE);if(mappages(pagetable, begin, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){kfree(mem);exit(-1);}vmprint(pagetable);}

因为释放进程内存的时候会通过页表释放堆空间,而很多堆空间并没有实际分配,即有效位为0,所以在uvmunmap中会panic,我们把相应的改为continue即可。

void
uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
{uint64 a;pte_t *pte;if((va % PGSIZE) != 0)panic("uvmunmap: not aligned");for(a = va; a < va + npages*PGSIZE; a += PGSIZE){if((pte = walk(pagetable, a, 0)) == 0)panic("uvmunmap: walk");if((*pte & PTE_V) == 0)continue;// panic("uvmunmap: not mapped");if(PTE_FLAGS(*pte) == PTE_V)panic("uvmunmap: not a leaf");if(do_free){uint64 pa = PTE2PA(*pte);kfree((void*)pa);}*pte = 0;}
}

运行echo hi,可以看到

$ echo hi
page table 0x0000000087f75000
..0: pte 0x0000000021fdc801 pa 0x0000000087f72000
.. ..0: pte 0x0000000021fd9401 pa 0x0000000087f65000
.. .. ..0: pte 0x0000000021fdc05f pa 0x0000000087f70000
.. .. ..1: pte 0x0000000021fd98df pa 0x0000000087f66000
.. .. ..2: pte 0x0000000021fdc40f pa 0x0000000087f71000
.. .. ..3: pte 0x0000000021fd68df pa 0x0000000087f5a000
.. .. ..4: pte 0x0000000021fd641f pa 0x0000000087f59000
..255: pte 0x0000000021fdd001 pa 0x0000000087f74000
.. ..511: pte 0x0000000021fdcc01 pa 0x0000000087f73000
.. .. ..510: pte 0x0000000021fd90c7 pa 0x0000000087f64000
.. .. ..511: pte 0x0000000020001c4b pa 0x0000000080007000
page table 0x0000000087f75000
..0: pte 0x0000000021fdc801 pa 0x0000000087f72000
.. ..0: pte 0x0000000021fd9401 pa 0x0000000087f65000
.. .. ..0: pte 0x0000000021fdc05f pa 0x0000000087f70000
.. .. ..1: pte 0x0000000021fd98df pa 0x0000000087f66000
.. .. ..2: pte 0x0000000021fdc40f pa 0x0000000087f71000
.. .. ..3: pte 0x0000000021fd68df pa 0x0000000087f5a000
.. .. ..4: pte 0x0000000021fd64df pa 0x0000000087f59000
.. .. ..19: pte 0x0000000021fd601f pa 0x0000000087f58000
..255: pte 0x0000000021fdd001 pa 0x0000000087f74000
.. ..511: pte 0x0000000021fdcc01 pa 0x0000000087f73000
.. .. ..510: pte 0x0000000021fd90c7 pa 0x0000000087f64000
.. .. ..511: pte 0x0000000020001c4b pa 0x0000000080007000
hi

有两次页面错误。

Lazytests and Usertests

这个我觉得有一定难度,如果没有提示的话很难考虑这么仔细。

按照提示一条条来

  • 处理sbrk()参数为负的情况。这个好处理,为负的情况依旧调用growproc处理即可:

    uint64
    sys_sbrk(void)
    {int addr;int n;struct proc * p = myproc(); if(argint(0, &n) < 0)return -1;addr = myproc()->sz;if(n > 0){p->sz = p->sz + n;}else{if (growproc(n) == -1) {return -1;}}return addr;
    }
    
  • 如果某个进程在高于sbrk()分配的任何虚拟内存地址上出现页错误,则终止该进程:页面错误中断的时候在分配新页面前检查是否高于p->sz。

  • fork()中正确处理父到子内存拷贝:这里的拷贝主要指的是uvmcopy,很简单,把这个函数里面前两个panic注释掉或者改成continue即可,因为在父进程中这些页也是没有实际存在的,子进程只要p->sz保持好的父进程一致就可以了。

  • 处理这种情形:进程从sbrk()向系统调用(如readwrite)传递有效地址,但尚未分配该地址的内存。这个是最难的,我们可以发现read或write的系统调用最终用的是copyout或者copyin,而这两者在walkaddr中如果找的是还没有实际分配页面的地址,那么发挥的物理地址就是0,从而系统调用返回-1,系统调用失败,在这个过程中并没有产生页面错误直接失败了,所以不会进入陷阱机制处理页面错误。所以要处理这种情况的话我们就要在walkaddr里面直接把没有实际分配的页面分配了,就像在trap中处理页面错误一样。

  • 正确处理内存不足:如果在页面错误处理程序中执行kalloc()失败,则终止当前进程。:如果kalloc返回的是0,则终止进程。

  • 处理用户栈下面的无效页面上发生的错误。如果虚拟地址va小于了用户栈,说明访问了不该访问的内存,终止进程。

综上,我们可以在vm.c里面写一个函数来分配映射lazy allocation的页面,如下:

// 注意:如果要在vm.c中使用proc结构体及其字段,要先加上"spinlock.h",再加上"proc.h"
int lazyalloc(uint64 va) {struct proc *p = myproc();// 如果高于sbrk的地址或者低于用户栈地址,终止进程if (va >= p->sz || va <= PGROUNDDOWN(p->trapframe->sp)) {return -1;}// printf("page fault:%p\n", va);uint64 begin = PGROUNDDOWN(va);pagetable_t pagetable = p->pagetable;char *mem = kalloc();if(mem == 0){return -1;}memset(mem, 0, PGSIZE);if(mappages(pagetable, begin, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){kfree(mem);return -1;}return 0;
}
// 需要在defs.h中加上这个函数的声明才能在其他地方使用这个函数

然后usertrap和walkaddr中调用这个函数

// usertrap
else if (r_scause() == 13 || r_scause() == 15) {uint64 va = r_stval();if (lazyalloc(va) == -1) {p->killed = 1;}}
uint64
walkaddr(pagetable_t pagetable, uint64 va)
{pte_t *pte;uint64 pa;if(va >= MAXVA)return 0;pte = walk(pagetable, va, 0);if(pte == 0 || (*pte & PTE_V) == 0) {if (lazyalloc(va) == -1) {return 0;} else {pte = walk(pagetable, va, 0);}}//   return 0;// if((*pte & PTE_V) == 0)//   return 0;if((*pte & PTE_U) == 0)return 0;pa = PTE2PA(*pte);return pa;
}

如果运行时出现了panic,把相应地方注释掉或者改为continue即可。

运行lazytests

$ lazytests
lazytests starting
running test lazy alloc
test lazy alloc: OK
running test lazy unmap
test lazy unmap: OK
running test out of memory
test out of memory: OK
ALL TESTS PASSED

运行usertests,可以看到所有测试通过,如果walkaddr编写的有问题的话,sbrkarg不会通过。

总结

这个实验总的来说我觉得还是比lab3简单一点,最需要注意的就是最后一个中关于系统调用涉及到lazy allocation不会触发页面错误需要手动编写代码来分配页面。

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

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

相关文章

Docker 一些设置

一、时间设置 如果容器已经运行了 docker exec -it 容器名或id bash mkdir -p /usr/share/zoneinfo/Asia exit docker cp /usr/share/zoneinfo/Asia/Shanghai 容器ID或容器名:/usr/share/zoneinfo/Asia docker exec -it 容器名或id bash cp /usr/share/zoneinfo/Asia/Shang…

【Https】HTTPS协议 的介绍及作用

HTTPS协议是一种安全的网络传输协议&#xff0c;它在传统的HTTP协议上加入了SSL/TLS加密层&#xff0c;用于保护数据传输的安全性和完整性。HTTPS协议是由HTTP和SSL层组成的&#xff0c;其中SSL&#xff08;安全套接层&#xff09;或其继任者TLS&#xff08;传输层安全协议&…

C++多态(详解)

一、多态的概念 1.1、多态的概念 多态&#xff1a;多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同的状态。 举个例子&#xff1a;比如买票这个行为&#xff0c;当普通人买票时&#xff0c;是全价买票&#xff1b;学生买票时&am…

【Python深度学习第二版】学习笔记之——神经网络

首先来说对于神经网络这几章看的很懵&#xff0c;虽然作者已经去掉了数学公式相关内容&#xff0c;讲得已经很想让读者容易理解了&#xff0c;奈何读完还是一知半解&#xff0c;下面就以我目前的理解简单记录一下吧&#xff0c;往后了解的多了再回头看一看。 一、张量运算 作…

故宫博物院与周大福珠宝集团 战略合作签约仪式在京举行

12月5日上午&#xff0c;故宫博物院与周大福珠宝集团战略合作签约仪式在故宫博物院故宫文化资产数字化应用研究所举行。文化和旅游部党组成员、故宫博物院院长王旭东&#xff0c;国际儒学联合会常务副会长、原文化部副部长丁伟&#xff0c;国际儒学联合会特别顾问、中国国际友好…

深入了解Java Duration类,对时间的精细操作

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概6000多字&#xff0c;预计阅读时间长需要5分钟。本篇文章的实战性、理论性较强&#xff0c;是一篇质量分数较高的技术干货文章&#x…

12.Java程序设计-基于Springboot框架的Android学习生活交流APP设计与实现

摘要 移动应用在日常生活中扮演着越来越重要的角色&#xff0c;为用户提供了方便的学习和生活交流渠道。本研究旨在设计并实现一款基于Spring Boot框架的Android学习生活交流App&#xff0c;以促进用户之间的信息分享、学术交流和社交互动。 在需求分析阶段&#xff0c;我们明…

如何使用HadSky搭配内网穿透工具搭建个人论坛并发布至公网随时随地可访问

文章目录 前言1. 网站搭建1.1 网页下载和安装1.2 网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3 Cpolar稳定隧道&#xff08;本地设置&#xff09;2.4 公网访问测试 总结 前言 经过多年的基础…

【微服务】springboot整合quartz使用详解

目录 一、前言 二、quartz介绍 2.1 quartz概述 2.2 quartz优缺点 2.3 quartz核心概念 2.3.1 Scheduler 2.3.2 Trigger 2.3.3 Job 2.3.4 JobDetail 2.4 Quartz作业存储类型 2.5 适用场景 三、Cron表达式 3.1 Cron表达式语法 3.2 Cron表达式各元素说明 3.3 Cron表达…

浅谈https

1.网络传输的安全性 http 协议&#xff1a;不安全&#xff0c;未加密https 协议&#xff1a;安全&#xff0c;对请求报文和响应报文做加密 2.对称加密与非对称加密 2.1 对称加密 特点&#xff1a; 加解密使用 相同 秘钥 高效&#xff0c;适用于大量数据的加密场景 算法公开&a…

C++STL的string类(一)

文章目录 前言C语言的字符串 stringstring类的常用接口string类的常见构造string (const string& str);string (const string& str, size_t pos, size_t len npos); capacitysize和lengthreserveresizeresize可以删除数据 modify尾插插入字符插入字符串 inserterasere…

7.3 Windows驱动开发:内核监视LoadImage映像回调

在笔者上一篇文章《内核注册并监控对象回调》介绍了如何运用ObRegisterCallbacks注册进程与线程回调&#xff0c;并通过该回调实现了拦截指定进行运行的效果&#xff0c;本章LyShark将带大家继续探索一个新的回调注册函数&#xff0c;PsSetLoadImageNotifyRoutine常用于注册Loa…

学习IO的第五天

作业 &#xff1a;使用两个线程完成文件的拷贝写入&#xff0c;分线程1写入前半段&#xff0c;分线程2写入后半段&#xff0c;主线程用来回收资源 #include <head.h>void *sork(void *arg); void *sork2(void *arg);int file_copy(int start,int len) //拷贝的函数 {i…

Linux_vi/vim编辑器

3.VI 与 VIM 3.1概述 vi编辑器&#xff1a;是Linux和Unix上最基本的文本编辑器&#xff0c;工作在字符模式下。由于不需要图形界面&#xff0c;vi是效率很高的文本编辑器。 vim是&#xff1a;vi的增强版&#xff0c;比vi更容易使用。vi的命令几乎全部都可以在vim上使用。 3…

Qt图形设计

#include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//窗口相关设置//设置窗口标题this->setWindowTitle("王者荣耀");//设置窗口图标this->setWindowIcon(QIcon("C:\\Users\\28033\\Pictures\\Saved Pictures\\pict…

ESP32单片机案例

工具&#xff1a;VScode PlatformIO IDE 注&#xff1a;B站视频学习笔记。 1、继电器 1&#xff09;硬件电路 2&#xff09;程序 #include <Arduino.h> #define RELAY_PIN 15//初始化定时器 hw_timer_t *timer NULL;void timer_interrupt(){ //将引脚传入的电平信号…

二、范围管理

1、范围管理的6个子过程 &#xff1a;规、集、定、创、确、控 规划范围管理&#xff1b; 收集需求&#xff1b; 定义范围&#xff1b; 创建WBS&#xff08;创建工作分解结构&#xff09;&#xff1b; 确认范围&#xff1b; 控制范围。 2、范围管理各过程的输入、输出、工具与…

公众号word文档

在数字化时代&#xff0c;信息的快速获取和高效整理变得尤为重要。微信公众号作为信息传播的重要平台&#xff0c;其内容经常需要被转换成更易于编辑和存档的格式&#xff0c;如Word文档。这里&#xff0c;我们将介绍如何利用“微附件”小程序实现这一过程&#xff0c;并分享一…

第二十一章

网络通信这一章 基本分为三个部分 网络基础概念和TCP,UDP这三个部分主要如下&#xff1a; 计算机网络实现了堕胎计算机间的互联&#xff0c;使得它们彼此之间能够进行数据交流。网络应用程序就是再已连接的不同计算机上运行的程序&#xff0c;这些程序借助于网络协议&#xf…

利用 Python 进行数据分析实验(三)

一、实验目的 使用Python解决简单问题 二、实验要求 自主编写并运行代码&#xff0c;按照模板要求撰写实验报告 三、实验步骤 本次实验共有4题&#xff1a; 自行给定一个从小到大排好序的数组&#xff0c;输入一个数并将其插入到原始数组中&#xff0c;新的数组还是满足从…