Skip to content

Commit

Permalink
wip(lab/7): update (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
Smallorange666 authored Jun 5, 2024
1 parent 22505b6 commit a0130fa
Showing 1 changed file with 17 additions and 16 deletions.
33 changes: 17 additions & 16 deletions docs/labs/0x07/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -766,17 +766,17 @@ pub struct Heap {
}
```

`Heap` 中,`base` 表示堆区的起始地址,`end` 表示堆区的结束地址`end` 是一个 `Arc<AtomicU64>` 类型的原子变量,因此它在多个进程的操作中被并发访问
`Heap` 中,`base` 表示堆区的起始地址,`end` 表示堆区的结束地址`end` 是一个 `Arc<AtomicU64>` 类型的可被共享的原子变量,它可以在多个进程的操作中被并发访问

> 也就是说,用户程序的堆区是在父子进程之间共享的,`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)]
Expand Down Expand Up @@ -814,19 +814,20 @@ pub fn brk(addr: Option<VirtAddr>) -> Option<VirtAddr> {
}
```

对于 `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();
Expand All @@ -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]
Expand All @@ -864,15 +863,17 @@ assert!(ret == heap_end, "Failed to allocate heap");
+ features = ["brk_alloc"]
```

4. 在你测试通过后,可以将其作为默认的内存分配器
4. 在你测试通过后,可以修改 `pkg/lib/Cargo.toml`,将其作为用户程序默认的内存分配器

```diff
[features]
- default = ["kernel_alloc"]
+ default = ["brk_alloc"]
```

如果想要实现一系列操作的自主测试,可以在自定义的用户程序中进行一系列的操作,或者直接将其实现为接受用户输入的 Shell 命令,进一步测试并记录你的 `brk` 系统调用的行为。
在后续的实验中,如果你想要自行实现内存管理算法,可以参考上述过程,通过添加 `feature` 对代码进行隔离,以便于测试和调试。

如果想要自主测试其他内存管理操作,可以修改自定义的用户程序,或者直接将其实现为接受用户输入的 Shell 命令,进一步测试并记录你的 `brk` 系统调用的行为。

!!! success "阶段性成果"

Expand Down

0 comments on commit a0130fa

Please sign in to comment.