当前位置: 首页 > news >正文

(undone) MIT6.S081 2023 学习笔记 (Day11: LAB10 mmap)

url: https://pdos.csail.mit.edu/6.1810/2023/labs/mmap.html


mmap和munmap系统调用允许UNIX程序对其地址空间进行精细控制。它们可用于进程间共享内存、将文件映射到进程地址空间,并作为用户级页面错误处理方案的一部分,例如课程中讨论的垃圾回收算法。在本实验中,您将向xv6添加mmap和munmap功能,重点关注内存映射文件。

The manual page (run man 2 mmap) shows this declaration for mmap:

void *mmap(void *addr, size_t len, int prot, int flags,int fd, off_t offset);

mmap 可以通过多种方式调用,但本实验仅需要实现与文件内存映射相关的部分功能。您可以假设 addr 始终为零,这意味着内核应自行决定文件的映射虚拟地址。mmap 会返回该地址,如果失败则返回 0xffffffffffffffff。len 是要映射的字节数,它可能与文件长度不同。prot 表示内存是否应映射为可读、可写和/或可执行;您可以假设 prot 是 PROT_READ 或 PROT_WRITE 或两者兼具。flags 可以是 MAP_SHARED(表示对映射内存的修改应写回文件)或 MAP_PRIVATE(表示不应写回文件),无需实现其他标志位。fd 是要映射的文件的打开文件描述符。您可以假设 offset 为零(即文件中的映射起始位置)。

即使映射相同 MAP_SHARED 文件的进程不共享物理页,也是允许的。

munmap 的手册页(运行 man 2 munmap)显示其声明如下:

int munmap(void *addr, size_t len);

munmap 应移除指定地址范围内的内存映射。如果进程修改了该内存区域且映射方式为 MAP_SHARED,则需先将修改内容写回文件。munmap 可能仅解除部分 mmap 映射区域,但可以假设其操作范围仅限于:从起始位置解除、从末尾解除,或解除整个区域(而不会在区域中间“打洞”解除部分映射)。

你需要实现足够的 mmap 和 munmap 功能,以确保 mmaptest 测试程序能够正常运行。如果 mmaptest 没有用到某个 mmap 的特性,你就不需要实现该特性。

When you’re done, you should see this output:

$ mmaptest
mmap_test starting
test mmap f
test mmap f: OK
test mmap private
test mmap private: OK
test mmap read-only
test mmap read-only: OK
test mmap read/write
test mmap read/write: OK
test mmap dirty
test mmap dirty: OK
test not-mapped unmap
test not-mapped unmap: OK
test mmap two files
test mmap two files: OK
mmap_test: ALL OK
fork_test starting
fork_test OK
mmaptest: all tests succeeded
$ usertests -q
usertests starting
...
ALL TESTS PASSED
$ 

以下是一些提示:

  • 首先,将 _mmaptest 添加到 UPROGS 中,并添加 mmap 和 munmap 系统调用,以便编译 user/mmaptest.c。目前,只需从 mmap 和 munmap 返回错误。我们在 kernel/fcntl.h 中为您定义了 PROT_READ 等。运行 mmaptest,它将在第一个 mmap 调用失败。
  • 在页面错误处理时懒加载页表。也就是说,mmap 不应分配物理内存或读取文件。相反,在 usertrap 中(或由 usertrap 调用的页面错误处理代码中)执行此操作,就像写时复制实验一样。懒加载的原因是为了确保对大文件的 mmap 快速,并且对大于物理内存的文件的 mmap 成为可能。
  • 跟踪每个进程 mmap 映射的内容。定义一个与“应用程序的虚拟内存”讲座中描述的 VMA(虚拟内存区域)相对应的结构。这应该记录由 mmap 创建的虚拟内存范围的地址、长度、权限、文件等。由于 xv6 内核中没有内核内存分配器,因此可以声明一个固定大小的 VMA 数组,并根据需要从中分配。大小为 16 应该足够。
  • 实现 mmap:在进程的地址空间中找到一个未使用的区域来映射文件,并将一个 VMA 添加到进程的映射区域表中。VMA 应该包含一个指向被映射文件的 struct file 的指针;mmap 应该增加文件的引用计数,以便在文件关闭时结构不会消失(提示:参见 filedup)。运行 mmaptest:第一个 mmap 应该成功,但是对 mmap-ed 内存的第一次访问将导致页面错误并杀死 mmaptest。
  • 添加代码以使 mmap-ed 区域的页面错误分配一个物理页面的内存,将相关文件的 4096 字节读取到该页面,并将其映射到用户地址空间。使用 readi 读取文件,该文件需要一个偏移参数来读取文件(但是您将不得不锁定/解锁传递给 readi 的 inode)。不要忘记正确设置页面的权限。运行 mmaptest;它应该到达第一个 munmap。
  • 实现 munmap:找到地址范围的 VMA 并取消映射指定的页面(提示:使用 uvmunmap)。如果 munmap 删除了之前 mmap 的所有页面,则应该减少相应 struct file 的引用计数。如果取消映射的页面已被修改并且文件被映射为 MAP_SHARED,则应将页面写回文件。查看 filewrite 以获取灵感。
  • 理想情况下,您的实现只会写回程序实际修改的 MAP_SHARED 页面。RISC-V PTE 中的脏位(D)指示页面是否已被写入。但是,mmaptest 不会检查未修改的页面是否没有被写回;因此,您可以不查看 D 位就写回页面。
  • 修改 exit 以取消映射进程的映射区域,就像调用了 munmap 一样。运行 mmaptest;mmap_test 应该通过,但可能不是 fork_test。
  • 修改 fork 以确保子进程具有与父进程相同的映射区域。不要忘记增加 VMA 的 struct file 的引用计数。在子进程的页面错误处理程序中,分配一个新的物理页面而不是与父进程共享页面是可以的。后者会更酷,但需要更多的实现工作。运行 mmaptest;它应该通过 mmap_test 和 fork_test。

运行 usertests -q 以确保一切仍然正常工作。

TODO: here


相关文章:

  • macOS 上是否有类似 WinRAR 的压缩软件?
  • android-ndk开发(2): macOS 安装 ndk
  • C++竞赛指南
  • Pinocchio导入URDF关节为continuous的问题及详细解释
  • 第二章-猜数游戏
  • 【bazel】bazel简介及简单使用
  • Qt实现网页内嵌
  • UDP协议(特点与应用场景)
  • cudaMalloc函数说明
  • 无人机 | 无人机设计概述
  • 某信服EDR3.5.30.ISO安装测试(一)
  • 【Java项目脚手架系列】第二篇:JavaWeb项目脚手架
  • 数据库MySQL学习——day9(聚合函数与分组数据)
  • 机器学习中常见搜索算法
  • Java基础学完,继续深耕(0505)Linux 常用命令
  • Python学习之路(七)-绘画and动画
  • 【Linux】linux入门——基本指令
  • 人工智能数学基础(十)—— 图论
  • 一个电商场景串联23种设计模式:创建型、结构型和行为型
  • Paramiko 核心类关系图解析
  • 建邦高科赴港上市,大股东陈子淳系山东建邦集团董事长陈箭之子
  • 习近平将对俄罗斯进行国事访问并出席纪念苏联伟大卫国战争胜利80周年庆典
  • 香港金紫荆广场举行五四升旗礼
  • 美国防部监察机构扩大“群聊门”事件调查范围
  • 五一假期上海口岸出入境客流总量预计达59.4万人,同比增约30%
  • 中国强镇密码丨洪泽湖畔的蒋坝,如何打破古镇刻板印象