diff --git a/crate/process/src/lib.rs b/crate/process/src/lib.rs index 1141518..dde6fee 100644 --- a/crate/process/src/lib.rs +++ b/crate/process/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![feature(alloc)] #![feature(const_fn)] +#![feature(linkage)] extern crate alloc; #[macro_use] diff --git a/crate/process/src/thread.rs b/crate/process/src/thread.rs index 1833af3..c9e8a6f 100644 --- a/crate/process/src/thread.rs +++ b/crate/process/src/thread.rs @@ -1,30 +1,10 @@ //! Thread std-like interface //! -//! Based on Processor. -//! Used in the kernel. +//! Based on Processor. Used in kernel. //! -//! # Example -//! -//! ``` -//! // 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; -//! ``` -//! -//! ``` -//! // Use it just like `std::thread` -//! use thread; -//! let t = thread::current(); -//! -//! // But the other struct is not available ... -//! let t: thread::Thread; // ERROR! -//! ``` +//! 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 use alloc::boxed::Box; use alloc::collections::BTreeMap; @@ -35,122 +15,121 @@ use processor::*; use process_manager::*; use scheduler::Scheduler; -/// All dependencies for thread mod. -pub trait ThreadSupport { - fn processor() -> &'static Processor; - fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box; +#[linkage = "weak"] +#[no_mangle] +/// Get a reference of the current `Processor` +fn processor() -> &'static Processor { + unimplemented!("thread: Please implement and export `processor`") } -/// Root structure served as thread mod -pub struct ThreadMod { - mark: PhantomData +#[linkage = "weak"] +#[no_mangle] +/// Construct a `Context` of the new kernel thread +fn new_kernel_context(entry: extern fn(usize) -> !, arg: usize) -> Box { + unimplemented!("thread: Please implement and export `new_kernel_context`") } -impl ThreadMod { - /// Gets a handle to the thread that invokes it. - pub fn current() -> Thread { - Thread { - pid: S::processor().pid(), - mark: PhantomData, - } + +/// Gets a handle to the thread that invokes it. +pub fn current() -> Thread { + Thread { + pid: processor().pid(), } +} - /// Puts the current thread to sleep for the specified amount of time. - pub fn sleep(dur: Duration) { - let time = dur_to_ticks(dur); - info!("sleep: {:?} ticks", time); - // TODO: register wakeup - Self::park(); +/// Puts the current thread to sleep for the specified amount of time. +pub fn sleep(dur: Duration) { + let time = dur_to_ticks(dur); + info!("sleep: {:?} ticks", time); + // TODO: register wakeup + park(); - fn dur_to_ticks(dur: Duration) -> usize { - return dur.as_secs() as usize * 100 + dur.subsec_nanos() as usize / 10_000_000; - } + fn dur_to_ticks(dur: Duration) -> usize { + return dur.as_secs() as usize * 100 + dur.subsec_nanos() as usize / 10_000_000; } +} - /// 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 +/// 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)); + + // 定义一个静态函数作为新线程的入口点 + // 其参数是函数f在堆上的指针 + // 这样我们就把函数f传到了一个静态函数内部 + // + // 注意到它具有泛型参数,因此对每一次spawn调用, + // 由于F类型是独特的,因此都会生成一个新的kernel_thread_entry + extern fn kernel_thread_entry(f: usize) -> ! 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: 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(); - // 让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!() - } + // 在静态函数内部: + // 根据传进来的指针,恢复f + let f = unsafe { Box::from_raw(f as *mut F) }; + // 调用f,并将其返回值也放在堆上 + let ret = Box::new(f()); + // 清理本地线程存储 + // unsafe { LocalKey::::get_map() }.clear(); + // 让Processor退出当前线程 + // 把f返回值在堆上的指针,以线程返回码的形式传递出去 + let pid = processor().pid(); + let exit_code = Box::into_raw(ret) as usize; + processor().manager().set_status(pid, Status::Exited(exit_code)); + processor().yield_now(); + // 再也不会被调度回来了 + unreachable!() + } - // 在Processor中创建新的线程 - let context = S::new_kernel(kernel_thread_entry::, f as usize); - let pid = S::processor().manager().add(context); + // 在Processor中创建新的线程 + let context = new_kernel_context(kernel_thread_entry::, f as usize); + let pid = processor().manager().add(context); - // 接下来看看`JoinHandle::join()`的实现 - // 了解是如何获取f返回值的 - return JoinHandle { - thread: Thread { pid, mark: PhantomData }, - mark: PhantomData, - }; - } + // 接下来看看`JoinHandle::join()`的实现 + // 了解是如何获取f返回值的 + return JoinHandle { + thread: Thread { pid }, + mark: PhantomData, + }; +} - /// Cooperatively gives up a timeslice to the OS scheduler. - pub fn yield_now() { - info!("yield:"); - S::processor().yield_now(); - } +/// Cooperatively gives up a timeslice to the OS scheduler. +pub fn yield_now() { + info!("yield:"); + processor().yield_now(); +} - /// Blocks unless or until the current thread's token is made available. - pub fn park() { - info!("park:"); - let pid = S::processor().pid(); - S::processor().manager().set_status(pid, Status::Sleeping); - S::processor().yield_now(); - } +/// Blocks unless or until the current thread's token is made available. +pub fn park() { + info!("park:"); + let pid = processor().pid(); + processor().manager().set_status(pid, Status::Sleeping); + processor().yield_now(); } /// A handle to a thread. -pub struct Thread { +pub struct Thread { pid: usize, - mark: PhantomData, } -impl Thread { +impl Thread { /// Atomically makes the handle's token available if it is not already. 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. pub fn id(&self) -> usize { @@ -159,14 +138,14 @@ impl Thread { } /// An owned permission to join on a thread (block on its termination). -pub struct JoinHandle { - thread: Thread, +pub struct JoinHandle { + thread: Thread, mark: PhantomData, } -impl JoinHandle { +impl JoinHandle { /// Extracts a handle to the underlying thread. - pub fn thread(&self) -> &Thread { + pub fn thread(&self) -> &Thread { &self.thread } /// Waits for the associated thread to finish. diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 73c6dbb..b8614ec 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -35,6 +35,8 @@ extern crate volatile; extern crate x86_64; extern crate xmas_elf; +pub use process::{processor, new_kernel_context}; +use ucore_process::thread; use linked_list_allocator::LockedHeap; #[macro_use] // print! @@ -46,8 +48,6 @@ mod consts; mod process; mod syscall; mod fs; - -use process::{thread, thread_}; mod sync; mod trap; mod console; diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 3f143da..3ec4a43 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -2,7 +2,6 @@ use spin::Once; use sync::{SpinNoIrqLock, Mutex, MutexGuard, SpinNoIrq}; pub use self::context::ContextImpl; pub use ucore_process::*; -pub use ucore_process::thread::*; use alloc::boxed::Box; use consts::MAX_CPU_NUM; 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()]; -pub fn processor() -> &'static Processor { - &PROCESSORS[cpu::id()] -} -#[allow(non_camel_case_types)] -pub type thread = ThreadMod; +// Implement dependencies for std::thread -pub mod thread_ { - pub type Thread = super::Thread; +#[no_mangle] +pub fn processor() -> &'static Processor { + &PROCESSORS[cpu::id()] } -pub struct ThreadSupportImpl; - -impl ThreadSupport for ThreadSupportImpl { - fn processor() -> &'static Processor { - processor() - } - fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Box { - ContextImpl::new_kernel(entry, arg) - } +#[no_mangle] +pub fn new_kernel_context(entry: extern fn(usize) -> !, arg: usize) -> Box { + ContextImpl::new_kernel(entry, arg) } \ No newline at end of file diff --git a/kernel/src/sync/condvar.rs b/kernel/src/sync/condvar.rs index 4dbbc78..5e14d2e 100644 --- a/kernel/src/sync/condvar.rs +++ b/kernel/src/sync/condvar.rs @@ -1,11 +1,10 @@ use alloc::collections::VecDeque; use super::*; use thread; -use thread_; #[derive(Default)] pub struct Condvar { - wait_queue: SpinNoIrqLock>, + wait_queue: SpinNoIrqLock>, } impl Condvar {