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