NetBSD 内存管理系统 UVM 浅析
2006-08-09 22:57:02 来源:WEB开发网观察 uvm_map 中的 vmspace_fork() 中对 MAP_INHERIT_COPY 情况的处理, 能够了解 amap 是怎么被创建和使用的, 而 fault 的处理, 即真正的 COW 过程, 我们将在 uvm_fault() 处解析.
我们来看 amap 和 anon 的具体管理实现.
anon 结构的声明在 uvm_anon.h 中, 有一个引用数, 一个 lock, 一个在未使用时指向下一未使用 anon 或在使用时指向 page 的指针. (anon 使用一个预分配的 anon 池完成 anon 的分配和释放), 以及标识该 anon 所管理的页在 swap 中的位置的 index, 非常易懂.
anon 的操作在 uvm_anon.c. 主要时 anon 的分配和释放, 以及一些 swap 系统的支持, 忽略之.
我们现在来看 amap 的数据接口, 主要是要注意 am_anon, am_bckptr, 和 am_slots 的关系, 在 uvm_amap.h:181 处的注释中有比较详细的解释. 它们结合起来实现对 anon 高效的查找和管理. 最后总结成一句最重要的话: "if am_anon[X] is non-NULL, then the following must be true: am_slots[am_bckptr[X]] == X".
下面来分析 uvm_amap.c, amap 本身的分配和释放过去简单, 忽略之, 我们主要观察:
amap 对 anon 的管理.
amap_add() 和 amap_unadd() 能加入/撤消一个 amap 对 anon 的链接, 代码在 uvm_amap_i.h 并不复杂, 主要是要在这里熟悉其数据结构的操作, 注意 amp_unadd() 保证删除一项后仍保持 am_slots 连续且有效的方法.
amap 对 COW 的支持.
amap_copy() 用于在 COW 的 write fault 发生的时候拷贝整个 amap 的表项, 以达到 COW 的效果 (想想 fork(2) 的传统处理过程). 这是 COW 的关键步骤.
首先, 如果要求处理的 entry 根本没有 amap --- 直接在 obj 上的 COW, 我们就先得创建一个. 然后, 我们得检查是否只有我们引用了这个 amap, 如果是刚刚新创建的 amap 就处于这种状态, 既然只有我们引用它, 那么 COW 的前提就不存在了, 直接忽略之. 之后, 我们就真要拷贝 amap 了, 我们拷贝的是对 amap 对 anon 的引用. 这时候, 我们就有了两个完全一样的 amap, 指向一样的 anon, 也就指向了同样的内存资源, 这样从我们看来就像是真正拷贝了内存资源一样, 但它们是只读的, 在第一次写 --- 也即要使它们不一样的时候, 我们才去做数据的拷贝和写操作, 这就是 COW 了.
更多精彩
赞助商链接