From a0130faf2e4d3d9a6c6583929a2e19646848be84 Mon Sep 17 00:00:00 2001 From: Smallorange666 <141314494+Smallorange666@users.noreply.github.com> Date: Wed, 5 Jun 2024 19:43:23 +0800 Subject: [PATCH] wip(lab/7): update (#37) --- docs/labs/0x07/tasks.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/docs/labs/0x07/tasks.md b/docs/labs/0x07/tasks.md index 21689f2..74c381d 100644 --- a/docs/labs/0x07/tasks.md +++ b/docs/labs/0x07/tasks.md @@ -766,17 +766,17 @@ pub struct Heap { } ``` -在 `Heap` 中,`base` 表示堆区的起始地址,`end` 表示堆区的结束地址,`end` 是一个 `Arc` 类型的原子变量,因此它在多个进程的操作中被并发访问。 +在 `Heap` 中,`base` 表示堆区的起始地址,`end` 表示堆区的结束地址。`end` 是一个 `Arc` 类型的可被共享的原子变量,它可以在多个进程的操作中被并发访问。 > 也就是说,用户程序的堆区是在父子进程之间共享的,`fork` 时不需要复制堆区内容,只需要复制 `Heap` 结构体即可。 -在本实验设计中,堆区的最大大小固定、起始地址固定,堆区的大小由 `end` 变量来控制,当用户程序调用 `brk` 系统调用时,内核会根据用户程序传入的参数来调整 `end` 的值,并进行相应的页面映射,从而调整堆区的大小。 +在本实验设计中,堆区的最大大小固定、起始地址固定,堆区的大小由 `end` 变量来控制。当用户程序调用 `brk` 系统调用时,内核会根据用户程序传入的参数来调整 `end` 的值,并进行相应的页面映射,从而调整堆区的大小。 > 如果你还是想和 Linux 对齐,`brk` 系统调用的调用号为 12。 下面对 `brk` 系统调用的参数和行为进行简单的约定。 -在用户态中,考虑下列系统调用函数封装:`brk` 系统调用的参数是一个可为 `None` 的指针,表示用户程序希望调整的堆区结束地址,用户参数采用 `0` 表示 `None`,返回值采用 `-1` 表示操作失败。 +在用户态中,考虑下列系统调用函数封装:`brk` 系统调用的参数是一个可为 `None` 的“指针”,表示用户程序希望调整的堆区结束地址,用户参数采用 `0` 表示 `None`,返回值采用 `-1` 表示操作失败。 ```rust #[inline(always)] @@ -814,19 +814,20 @@ pub fn brk(addr: Option) -> Option { } ``` -对于 `brk` 系统调用的具体实现,你需要在 `pkg/kernel/src/proc/vm/heap.rs` 中为 `Heap` 结构体实现 `brk` 函数: +最终,你需要在 `pkg/kernel/src/proc/vm/heap.rs` 中为 `Heap` 结构体实现 `brk` 函数: - 如果参数为 `None`,则表示用户程序希望获取当前的堆区结束地址,即返回 `end` 的值; -- 如果用户程序传入的参数不为 `None`,则检查用户传入的地址是否合法,即在 `[HEAP_START, HEAP_END]` 区间内,如果不合法则返回 `None`。 +- 如果参数不为 `None`,则检查用户传入的目标地址是否合法,即是否在 `[HEAP_START, HEAP_END]` 区间内,如果不合法,直接返回 `None`。 -对于有效输入的处理,需要满足如下约定: +如果目标地址合法,则按照以下约定处理: - 初始化堆区时,`base` 和 `end` 的值均为 `HEAP_START`; -- 用户希望释放整个堆区:传入地址为 `base`,释放所有页面,`end` 重置为 `base`; -- 用户希望缩小堆区:传入地址比当前 `end` 小,对目的地址向上对齐到页边界,释放多余的页面; -- 用户希望扩大堆区:传入地址比当前 `end` 大,对目的地址向上对齐到页边界,分配新的页面。 +- 用户希望释放整个堆区:目标地址为 `base`,释放所有页面,`end` 重置为 `base`; +- 用户希望缩小堆区:目标地址比当前 `end` 小,先将目标地址向上对齐到页边界,然后释放多余的页面; +- 用户希望扩大堆区:目标地址比当前 `end` 大,先将目标地址向上对齐到页边界,然后分配的页面; +- 若调整成功,返回新的堆区终止地址;否则返回 `None`。 -对于一段典型的系统调用过程,可以参考如下代码: +用户程序中,一段典型的调整堆的系统调用过程,可以参考如下代码: ```rust let heap_start = sys_brk(None).unwrap(); @@ -845,13 +846,11 @@ assert!(ret == heap_end, "Failed to allocate heap"); 1. 新建一个用户程序,参考上述代码,尝试在其中使用 `brk` 系统调用来调整堆区的大小,并进行写入和读取操作; -2. 若上述操作没有问题,则可以在 `lib` 中实现可选的第二个内存分配器(参考给出代码 `pkg/lib/src/allocator/brk.rs`); +2. 若上述操作没有问题,则可以在 `lib` 中实现可选的第二个内存分配器(代码已在 `pkg/lib/src/allocator/brk.rs` 给出); 内存分配器的自主实现不是本次实验的内容,因此这里直接使用 `linked_list_allocator` 进行代劳。 - 在后续的实验中,如果你想要自行实现内存管理算法,可以参考给出的方式添加 `feature` 对代码进行隔离,以便于测试和调试。 - -3. 尝试在进程中使用如下方式来暂时使用新的内存分配器: +3. 尝试使用新的内存分配器,可以按如下方式修改用户程序的 `Cargo.toml`: ```diff [dependencies] @@ -864,7 +863,7 @@ assert!(ret == heap_end, "Failed to allocate heap"); + features = ["brk_alloc"] ``` -4. 在你测试通过后,可以将其作为默认的内存分配器: +4. 在你测试通过后,可以修改 `pkg/lib/Cargo.toml`,将其作为用户程序默认的内存分配器: ```diff [features] @@ -872,7 +871,9 @@ assert!(ret == heap_end, "Failed to allocate heap"); + default = ["brk_alloc"] ``` -如果想要实现一系列操作的自主测试,可以在自定义的用户程序中进行一系列的操作,或者直接将其实现为接受用户输入的 Shell 命令,进一步测试并记录你的 `brk` 系统调用的行为。 +在后续的实验中,如果你想要自行实现内存管理算法,可以参考上述过程,通过添加 `feature` 对代码进行隔离,以便于测试和调试。 + +如果想要自主测试其他内存管理操作,可以修改自定义的用户程序,或者直接将其实现为接受用户输入的 Shell 命令,进一步测试并记录你的 `brk` 系统调用的行为。 !!! success "阶段性成果"