rCore-Tutorial-Book-v3
rCore-Tutorial-Book-v3 copied to clipboard
rCore-Tutorial-Book-v3/chapter5/3implement-process-mechanism
进程管理机制的设计实现 — rCore-Tutorial-Book-v3 0.1 文档
https://rcore-os.github.io/rCore-Tutorial-Book-v3/chapter5/3implement-process-mechanism.html
有个问题, 我觉得MemorySet::recycle_data_pages
这个函数并不必要, 因为areas是MemorySet的一个成员, 而MemorySet是TaskControlBlock的成员, 父进程回收子进程的时候, remove子进程TaskControlBlock(这里说得不严谨, 应该是child生命周期结束)会连锁释放掉areas, 不就自动清空了么?
@Tokubara 在 exit_current_and_run_next
中我们会手动调用 recycle_data_page
来提前手动回收掉保存应用数据的所有物理页帧,因为它们已经不会再被用到了。如果等到父进程整体回收子进程TCB的时候由编译器自动回收它们,会使得这部分物理页帧被闲置一段时间,没有得到充分利用。
- 字符输入机制:为了 ~~支对~~ shell程序-user_shell获得字符输入,介绍 sys_read 系统调用的实现;
- 字符输入机制:为了 支持 shell程序-user_shell获得字符输入,介绍 sys_read 系统调用的实现;
第 26 行,我们让子进程和父进程的 base_size ,也即应用数据的大小保持一致;
应该是 24 行。
pub fn from_existed_user(user_space: &MemorySet) -> MemorySet { ... }
MemorySet::from_existed_user
起到的就是 Clone 的作用,或许直接实现 Clone 或至少改为
pub fn from_existed_user(another: &Self) -> Self { ... }
更清楚一些?
第 26 行,我们让子进程和父进程的 base_size ,也即应用数据的大小保持一致;
应该是 24 行。
pub fn from_existed_user(user_space: &MemorySet) -> MemorySet { ... }
MemorySet::from_existed_user
起到的就是 Clone 的作用,或许直接实现 Clone 或至少改为pub fn from_existed_user(another: &Self) -> Self { ... }
更清楚一些?
struct MapArea
中也有类似的情况,我觉得实现Clone应该会更合理一些
exec用新的elf数据替换当前进程的数据,这里inner中的base_size没有重新设置,虽然这个base_size在这章没有用到,但也应该设置一下吧:
pub fn exec(&self, elf_data: &[u8]) {
// memory_set with elf program headers/trampoline/trap context/user stack
let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data);
let trap_cx_ppn = memory_set
.translate(VirtAddr::from(TRAP_CONTEXT).into())
.unwrap()
.ppn();
// **** access inner exclusively
let mut inner = self.inner_exclusive_access();
// substitute memory_set
inner.memory_set = memory_set;
// update trap_cx ppn
inner.trap_cx_ppn = trap_cx_ppn;
// initialize trap_cx
let trap_cx = inner.get_trap_cx();
*trap_cx = TrapContext::app_init_context(
entry_point,
user_sp,
KERNEL_SPACE.exclusive_access().token(),
self.kernel_stack.get_top(),
trap_handler as usize,
);
// **** release inner automatically
}
@YdrMaster @MrZLeo @CtrlZ233 初步按照几位的建议更新了一下代码,详见这里。其他分支后续更新。
第 16~18 行我们为该进程分配 PID 以及内核栈……
应为 17-19 行
您好,我关于源码中 translated_refmut
的实现有些疑惑,具体的代码如下:
pub fn translated_refmut<T>(token: usize, ptr: *mut T) -> &'static mut T {
let page_table = PageTable::from_token(token);
let va = ptr as usize;
page_table
.translate_va(VirtAddr::from(va))
.unwrap()
.get_mut()
}
这个函数以 <T>
的指针作为参数传入,而后传出一个该指针对应的物理地址,这个指针所指向的类型为 <T>
。但是如果这个 <T>
的大小比 u8
大,是否有可能会导致返回的指针虽然确实是一个正确的 ptr
所对应的物理地址的开始,但 <T>
的数据虽然在虚拟地址上连贯,但有可能实际在不同的并且 ppn
不连贯的物理页上?
结果可能就是 <T>
的部分数据确实正确写入了,但是另一部分数据却写入了前半部分数据那一页所存储的物理页的连贯的下一个物理页,而这可能并不是正确的下一个物理页。我猜测这样可能导致后半部分的数据丢失,或者覆盖了其他区域正确的数据。
以上仅是我的猜测,还烦请大家帮忙解答一下。
@KujouRinka 我忘了文档中有没有提到,其实translated_refmut
(还有一些类似的接口也是这样)要求类型T
是原生类型,比如u8,u16,u32,u64
这些,也就是其大小能整除页的大小,同时起始地址是对齐的。这样的话,就不会出现你说的那种情况了。后面可以考虑加一个静态检查?
首先是从 ELF 文件生成一个全新的地址空间并直接替换进来(第 15 行),这将导致原有的地址空间生命周期结束,里面包含的全部物理页帧都会被回收;
exec里面会回收掉老的memoryset结构,但其实只是放到一个全局结构里存着,并不会抹除物理页上的内容,而且satp也没改,还是老的memoryset的token,这个地方是设计如此吗?
如果控制流在回到应用程序之前,发生了分配物理页而且刚好是satp对应的那个物理页,然后被写入内容覆盖了,是不是就会出问题了?
idle_task_cx 难懂的原因是,Processor::new() 初始化时它被设置为全0,但整个项目又似乎找不到修改它的代码!难道idle_task_cx一直都是0吗?
idle_task_cx一开始确实是全0,当内核启动从rust_main()进入run_tasks()后,在loop第一句PROCESSOR.exclusive_access()访问PROCESSOR前,PROCESSOR被初始化,这个时候idle_task_cx是全0,然后拿到idle_task_cx的指针,注意是指针,最后在__switch(idle_task_cx_ptr, next_task_cx_ptr)
的调用中带着idle_task_cx的指针进入__switch函数,__switch函数就将当前的上下文通过idle_task_cx指针存到了PROCESSOR当中,这个时候idle_task_cx就从全0变成了run_tasks()里loop的上下文
有一个疑问寻求有缘人解答: 我运行了ch5分支的代码, 在trap_handler的中断加了打印
Trap::Interrupt(Interrupt::SupervisorTimer) => {
set_next_trigger();
println!("trap::Interrupt---------------------");
suspend_current_and_run_next();
}
发现执行make run到进入user_shell后, 如果不输入字符, 就再也不会进入中断 我的疑问是, 为啥这时时钟中断没有生效? 不应该隔一段时间就陷入中断吗?
有一个疑问寻求有缘人解答: 我运行了ch5分支的代码, 在trap_handler的中断加了打印
Trap::Interrupt(Interrupt::SupervisorTimer) => { set_next_trigger(); println!("trap::Interrupt---------------------"); suspend_current_and_run_next(); }
发现执行make run到进入user_shell后, 如果不输入字符, 就再也不会进入中断 我的疑问是, 为啥这时时钟中断没有生效? 不应该隔一段时间就陷入中断吗?
控制台无输入时, 处于sys_read
的循环中,程序一直保持内核态,此时不会被时钟中断打断 抢占式调度