diff --git a/crate/process/src/thread.rs b/crate/process/src/thread.rs index 8786cc8..818a28a 100644 --- a/crate/process/src/thread.rs +++ b/crate/process/src/thread.rs @@ -73,34 +73,61 @@ impl ThreadMod { } /// Spawns a new thread, returning a JoinHandle for it. + /// + /// `F`: Type of the function `f` + /// `T`: Type of the return value of `f` pub fn spawn(f: F) -> JoinHandle where F: Send + 'static + FnOnce() -> T, T: Send + 'static, { info!("spawn:"); + + // 注意到下面的问题: + // Processor只能从入口地址entry+参数arg创建新线程 + // 而我们现在需要让它执行一个未知类型的(闭包)函数f + + // 首先把函数本体(代码数据)置于堆空间中 let f = Box::into_raw(Box::new(f)); - let pid = S::processor().add(Context::new_kernel(kernel_thread_entry::, f as usize)); - return JoinHandle { - thread: Thread { pid, mark: PhantomData }, - mark: PhantomData, - }; + // 定义一个静态函数作为新线程的入口点 + // 其参数是函数f在堆上的指针 + // 这样我们就把函数f传到了一个静态函数内部 + // + // 注意到它具有泛型参数,因此对每一次spawn调用, + // 由于F类型是独特的,因此都会生成一个新的kernel_thread_entry extern fn kernel_thread_entry(f: usize) -> ! where S: ThreadSupport, F: Send + 'static + FnOnce() -> T, T: Send + 'static, { + // 在静态函数内部: + // 根据传进来的指针,恢复f let f = unsafe { Box::from_raw(f as *mut F) }; + // 调用f,并将其返回值也放在堆上 let ret = Box::new(f()); -// unsafe { LocalKey::::get_map() }.clear(); + // 清理本地线程存储 + // unsafe { LocalKey::::get_map() }.clear(); + // 让Processor退出当前线程 + // 把f返回值在堆上的指针,以线程返回码的形式传递出去 let mut processor = S::processor(); let pid = processor.current_pid(); processor.exit(pid, Box::into_raw(ret) as usize); processor.schedule(); + // 再也不会被调度回来了 unreachable!() } + + // 在Processor中创建新的线程 + let pid = S::processor().add(Context::new_kernel(kernel_thread_entry::, f as usize)); + + // 接下来看看`JoinHandle::join()`的实现 + // 了解是如何获取f返回值的 + return JoinHandle { + thread: Thread { pid, mark: PhantomData }, + mark: PhantomData, + }; } /// Cooperatively gives up a timeslice to the OS scheduler. @@ -155,6 +182,7 @@ impl JoinHandle { let mut processor = S::processor(); match processor.current_wait_for(self.thread.pid) { WaitResult::Ok(_, exit_code) => unsafe { + // Find return value on the heap from the exit code. Ok(*Box::from_raw(exit_code as *mut T)) } WaitResult::NotExist => Err(()),