返回介绍

proj9.2:实现写时复制

发布于 2025-02-16 22:47:55 字数 1473 浏览 0 评论 0 收藏 0

proj9.2 实现了写时复制(Copy On Write,简称 COW)的主要功能,为 lab3 高效地创建子进程打下了基础。COW 有何作用?这里又不得不提前讲讲 lab3 中的子进程创建。不同的进程应该具有不同的物理内存空间,当用户态进程发出 fork( ) 系统调用来创建子进程时,ucore 可复制当前进程(父进程)的整个地址空间,这样就有两块不同的物理地址空间了,新复制的那一块物理地址空间分配给子进程。这种行为是非常耗时和占内存资源的,因为它需要为子进程的页表分配页面,复制父进程的每一个物理内存页。如果子进程加载一个新的程序开始执行(这个过程会释放掉原来申请的全部内存和资源),这样前面的复制工作就白做了,完全没有必要。

为了解决上述问题,ucore 采用一种有效的 COW 机制。其设计思想相对简单:父进程和子进程之间共享(share)页面而不是复制(copy)页面。但只要页面被共享,它们就不能被修改,即是只读的。注意此共享是指父子进程共享一个表示内存空间的 mm_struct 结构的变量。当父进程或子进程试图写一个共享的页面,就产生一个页访问异常,这时内核就把这个页复制到一个新的页面中并标记为可写。注意,原来的页面仍然是写保护的。当其它进程试图写入时,ucore 检查写进程是否是这个页面的唯一属主(通过判断 page_ref 和 swap_page_count 即 mem_map 中相关 entry 保存的值的和是否为 1。注意区分与 share memory 的差别,share memory 通过 vma 中的 shmem 实现,这样的 page 是直接标记为共享的,而不是 copy on write,所以也没有任何冲突);如果是,它把这个页面标记为对这个进程是可写的。

在具体实现上,ucore 调用 dup_mmap 函数,并进一步调用 copy_range 函数来具体完成对页表内容的复制,这样两个页表表示同一个虚拟地址空间(包括对应的物理地址空间),且还需修改两个页表中每一个页对应的页表项属性为只读,但。在这种情况下,两个进程有两个页表,但这两个页表只映射了一块只读的物理内存。同理,对于换出的页,也采用同样的办法来共享一个换出页。综上所述,我们可以总结出:如果一个页的 PTE 属性是只读的,但此页所属的 VMA 描述指出其虚地址空间是可写的,则这样的页是 COW 页。

当对这样的地址空间进行写操作的时候,会触发 do_pgfault 函数被调用。此函数如果发现是 COW 页,就会调用 alloc_page 函数新分配一个物理页,并调用 memcpy 函数把旧页的内容复制到新页中,并最后调用 page_insert 函数给当前产生缺页错的进程建立虚拟页地址到新物理页地址的映射关系(即改写 PTE,并设置此页为可读写)。

这里还有一个特殊情况,如果产生访问异常的页已经被换出到硬盘上了,则需要把此页通过 swap_in_page 函数换入到内存中来,如果进一步发现换入的页是一个 COW 页,则把其属性设置为只读,然后异常处理结束返回。但这样重新执行产生异常的写操作,又会触发一次内存访问异常,则又要执行上一段描述的过程了。

Page 结构的 ref 域用于跟踪共享相应页面的进程数目。只要进程释放一个页面或者在它上面执行写时复制,它的 ref 域就递减;只有当 ref 变为 0 时,这个页面才被释放。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文