Use weak linkage to provide dependencies for process::thread.

master
WangRunji 6 years ago
parent 80b161db98
commit 85a1dca684

@ -1,6 +1,7 @@
#![no_std] #![no_std]
#![feature(alloc)] #![feature(alloc)]
#![feature(const_fn)] #![feature(const_fn)]
#![feature(linkage)]
extern crate alloc; extern crate alloc;
#[macro_use] #[macro_use]

@ -1,30 +1,10 @@
//! Thread std-like interface //! Thread std-like interface
//! //!
//! Based on Processor. //! Based on Processor. Used in kernel.
//! Used in the kernel.
//! //!
//! # Example //! You need to implement the following functions before use:
//! //! - `processor`: Get a reference of the current `Processor`
//! ``` //! - `new_kernel_context`: Construct a `Context` of the new kernel thread
//! // Define a support implementation struct
//! pub struct ThreadSupportImpl;
//!
//! // Impl `ThreadSupport` trait
//! impl ThreadSupport for ThreadSupportImpl { ... }
//!
//! // Export the full struct as `thread`.
//! #[allow(non_camel_case_types)]
//! pub type thread = ThreadMod<ThreadSupportImpl>;
//! ```
//!
//! ```
//! // Use it just like `std::thread`
//! use thread;
//! let t = thread::current();
//!
//! // But the other struct is not available ...
//! let t: thread::Thread; // ERROR!
//! ```
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::collections::BTreeMap; use alloc::collections::BTreeMap;
@ -35,122 +15,121 @@ use processor::*;
use process_manager::*; use process_manager::*;
use scheduler::Scheduler; use scheduler::Scheduler;
/// All dependencies for thread mod. #[linkage = "weak"]
pub trait ThreadSupport { #[no_mangle]
fn processor() -> &'static Processor; /// Get a reference of the current `Processor`
fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box<Context>; fn processor() -> &'static Processor {
unimplemented!("thread: Please implement and export `processor`")
} }
/// Root structure served as thread mod #[linkage = "weak"]
pub struct ThreadMod<S: ThreadSupport> { #[no_mangle]
mark: PhantomData<S> /// Construct a `Context` of the new kernel thread
fn new_kernel_context(entry: extern fn(usize) -> !, arg: usize) -> Box<Context> {
unimplemented!("thread: Please implement and export `new_kernel_context`")
} }
impl<S: ThreadSupport> ThreadMod<S> {
/// Gets a handle to the thread that invokes it. /// Gets a handle to the thread that invokes it.
pub fn current() -> Thread<S> { pub fn current() -> Thread {
Thread { Thread {
pid: S::processor().pid(), pid: processor().pid(),
mark: PhantomData,
}
} }
}
/// Puts the current thread to sleep for the specified amount of time. /// Puts the current thread to sleep for the specified amount of time.
pub fn sleep(dur: Duration) { pub fn sleep(dur: Duration) {
let time = dur_to_ticks(dur); let time = dur_to_ticks(dur);
info!("sleep: {:?} ticks", time); info!("sleep: {:?} ticks", time);
// TODO: register wakeup // TODO: register wakeup
Self::park(); park();
fn dur_to_ticks(dur: Duration) -> usize { fn dur_to_ticks(dur: Duration) -> usize {
return dur.as_secs() as usize * 100 + dur.subsec_nanos() as usize / 10_000_000; return dur.as_secs() as usize * 100 + dur.subsec_nanos() as usize / 10_000_000;
}
} }
}
/// Spawns a new thread, returning a JoinHandle for it. /// Spawns a new thread, returning a JoinHandle for it.
/// ///
/// `F`: Type of the function `f` /// `F`: Type of the function `f`
/// `T`: Type of the return value of `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<T>
where
F: Send + 'static + FnOnce() -> T,
T: Send + 'static,
{
info!("spawn:");
// 注意到下面的问题:
// Processor只能从入口地址entry+参数arg创建新线程
// 而我们现在需要让它执行一个未知类型的闭包函数f
// 首先把函数本体(代码数据)置于堆空间中
let f = Box::into_raw(Box::new(f));
// 定义一个静态函数作为新线程的入口点
// 其参数是函数f在堆上的指针
// 这样我们就把函数f传到了一个静态函数内部
//
// 注意到它具有泛型参数因此对每一次spawn调用
// 由于F类型是独特的因此都会生成一个新的kernel_thread_entry
extern fn kernel_thread_entry<F, T>(f: usize) -> !
where where
F: Send + 'static + FnOnce() -> T, F: Send + 'static + FnOnce() -> T,
T: Send + 'static, T: Send + 'static,
{ {
info!("spawn:"); // 在静态函数内部:
// 根据传进来的指针恢复f
// 注意到下面的问题: let f = unsafe { Box::from_raw(f as *mut F) };
// Processor只能从入口地址entry+参数arg创建新线程 // 调用f并将其返回值也放在堆上
// 而我们现在需要让它执行一个未知类型的闭包函数f let ret = Box::new(f());
// 清理本地线程存储
// 首先把函数本体(代码数据)置于堆空间中 // unsafe { LocalKey::<usize>::get_map() }.clear();
let f = Box::into_raw(Box::new(f)); // 让Processor退出当前线程
// 把f返回值在堆上的指针以线程返回码的形式传递出去
// 定义一个静态函数作为新线程的入口点 let pid = processor().pid();
// 其参数是函数f在堆上的指针 let exit_code = Box::into_raw(ret) as usize;
// 这样我们就把函数f传到了一个静态函数内部 processor().manager().set_status(pid, Status::Exited(exit_code));
// processor().yield_now();
// 注意到它具有泛型参数因此对每一次spawn调用 // 再也不会被调度回来了
// 由于F类型是独特的因此都会生成一个新的kernel_thread_entry unreachable!()
extern fn kernel_thread_entry<S, F, T>(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::<usize>::get_map() }.clear();
// 让Processor退出当前线程
// 把f返回值在堆上的指针以线程返回码的形式传递出去
let pid = S::processor().pid();
let exit_code = Box::into_raw(ret) as usize;
S::processor().manager().set_status(pid, Status::Exited(exit_code));
S::processor().yield_now();
// 再也不会被调度回来了
unreachable!()
}
// 在Processor中创建新的线程 // 在Processor中创建新的线程
let context = S::new_kernel(kernel_thread_entry::<S, F, T>, f as usize); let context = new_kernel_context(kernel_thread_entry::<F, T>, f as usize);
let pid = S::processor().manager().add(context); let pid = processor().manager().add(context);
// 接下来看看`JoinHandle::join()`的实现 // 接下来看看`JoinHandle::join()`的实现
// 了解是如何获取f返回值的 // 了解是如何获取f返回值的
return JoinHandle { return JoinHandle {
thread: Thread { pid, mark: PhantomData }, 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.
pub fn yield_now() { pub fn yield_now() {
info!("yield:"); info!("yield:");
S::processor().yield_now(); processor().yield_now();
} }
/// Blocks unless or until the current thread's token is made available. /// Blocks unless or until the current thread's token is made available.
pub fn park() { pub fn park() {
info!("park:"); info!("park:");
let pid = S::processor().pid(); let pid = processor().pid();
S::processor().manager().set_status(pid, Status::Sleeping); processor().manager().set_status(pid, Status::Sleeping);
S::processor().yield_now(); processor().yield_now();
}
} }
/// A handle to a thread. /// A handle to a thread.
pub struct Thread<S: ThreadSupport> { pub struct Thread {
pid: usize, pid: usize,
mark: PhantomData<S>,
} }
impl<S: ThreadSupport> Thread<S> { impl Thread {
/// Atomically makes the handle's token available if it is not already. /// Atomically makes the handle's token available if it is not already.
pub fn unpark(&self) { pub fn unpark(&self) {
S::processor().manager().set_status(self.pid, Status::Ready); processor().manager().set_status(self.pid, Status::Ready);
} }
/// Gets the thread's unique identifier. /// Gets the thread's unique identifier.
pub fn id(&self) -> usize { pub fn id(&self) -> usize {
@ -159,14 +138,14 @@ impl<S: ThreadSupport> Thread<S> {
} }
/// An owned permission to join on a thread (block on its termination). /// An owned permission to join on a thread (block on its termination).
pub struct JoinHandle<S: ThreadSupport, T> { pub struct JoinHandle<T> {
thread: Thread<S>, thread: Thread,
mark: PhantomData<T>, mark: PhantomData<T>,
} }
impl<S: ThreadSupport, T> JoinHandle<S, T> { impl<T> JoinHandle<T> {
/// Extracts a handle to the underlying thread. /// Extracts a handle to the underlying thread.
pub fn thread(&self) -> &Thread<S> { pub fn thread(&self) -> &Thread {
&self.thread &self.thread
} }
/// Waits for the associated thread to finish. /// Waits for the associated thread to finish.

@ -35,6 +35,8 @@ extern crate volatile;
extern crate x86_64; extern crate x86_64;
extern crate xmas_elf; extern crate xmas_elf;
pub use process::{processor, new_kernel_context};
use ucore_process::thread;
use linked_list_allocator::LockedHeap; use linked_list_allocator::LockedHeap;
#[macro_use] // print! #[macro_use] // print!
@ -46,8 +48,6 @@ mod consts;
mod process; mod process;
mod syscall; mod syscall;
mod fs; mod fs;
use process::{thread, thread_};
mod sync; mod sync;
mod trap; mod trap;
mod console; mod console;

@ -2,7 +2,6 @@ use spin::Once;
use sync::{SpinNoIrqLock, Mutex, MutexGuard, SpinNoIrq}; use sync::{SpinNoIrqLock, Mutex, MutexGuard, SpinNoIrq};
pub use self::context::ContextImpl; pub use self::context::ContextImpl;
pub use ucore_process::*; pub use ucore_process::*;
pub use ucore_process::thread::*;
use alloc::boxed::Box; use alloc::boxed::Box;
use consts::MAX_CPU_NUM; use consts::MAX_CPU_NUM;
use arch::cpu; use arch::cpu;
@ -33,24 +32,15 @@ pub fn init() {
static PROCESSORS: [Processor; MAX_CPU_NUM] = [Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new()]; static PROCESSORS: [Processor; MAX_CPU_NUM] = [Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new(), Processor::new()];
pub fn processor() -> &'static Processor {
&PROCESSORS[cpu::id()]
}
#[allow(non_camel_case_types)] // Implement dependencies for std::thread
pub type thread = ThreadMod<ThreadSupportImpl>;
pub mod thread_ { #[no_mangle]
pub type Thread = super::Thread<super::ThreadSupportImpl>; pub fn processor() -> &'static Processor {
&PROCESSORS[cpu::id()]
} }
pub struct ThreadSupportImpl; #[no_mangle]
pub fn new_kernel_context(entry: extern fn(usize) -> !, arg: usize) -> Box<Context> {
impl ThreadSupport for ThreadSupportImpl { ContextImpl::new_kernel(entry, arg)
fn processor() -> &'static Processor {
processor()
}
fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box<Context> {
ContextImpl::new_kernel(entry, arg)
}
} }

@ -1,11 +1,10 @@
use alloc::collections::VecDeque; use alloc::collections::VecDeque;
use super::*; use super::*;
use thread; use thread;
use thread_;
#[derive(Default)] #[derive(Default)]
pub struct Condvar { pub struct Condvar {
wait_queue: SpinNoIrqLock<VecDeque<thread_::Thread>>, wait_queue: SpinNoIrqLock<VecDeque<thread::Thread>>,
} }
impl Condvar { impl Condvar {

Loading…
Cancel
Save