//! Thread std-like interface //! //! Based on Processor. //! Used in the 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! //! ``` use alloc::boxed::Box; use alloc::BTreeMap; use core::any::Any; use core::marker::PhantomData; use core::ptr; use core::time::Duration; use core::ops::DerefMut; use processor::*; use scheduler::Scheduler; /// All dependencies for thread mod. pub trait ThreadSupport { type Context: Context; type Scheduler: Scheduler; type ProcessorGuard: DerefMut>; fn processor() -> Self::ProcessorGuard; } /// Root structure served as thread mod pub struct ThreadMod { mark: PhantomData } impl ThreadMod { /// Gets a handle to the thread that invokes it. pub fn current() -> Thread { Thread { pid: S::processor().current_pid(), mark: PhantomData, } } /// 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); let mut processor = S::processor(); let pid = processor.current_pid(); processor.sleep(pid, time); processor.schedule(); 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. pub fn spawn(f: F) -> JoinHandle where F: Send + 'static + FnOnce() -> T, T: Send + 'static, { info!("spawn:"); 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, }; extern fn kernel_thread_entry(f: usize) -> ! where S: ThreadSupport, F: Send + 'static + FnOnce() -> T, T: Send + 'static, { let f = unsafe { Box::from_raw(f as *mut F) }; let ret = Box::new(f()); // unsafe { LocalKey::::get_map() }.clear(); let mut processor = S::processor(); let pid = processor.current_pid(); processor.exit(pid, Box::into_raw(ret) as usize); processor.schedule(); unreachable!() } } /// Cooperatively gives up a timeslice to the OS scheduler. pub fn yield_now() { info!("yield:"); let mut processor = S::processor(); processor.set_reschedule(); processor.schedule(); } /// Blocks unless or until the current thread's token is made available. pub fn park() { info!("park:"); let mut processor = S::processor(); let pid = processor.current_pid(); processor.sleep_(pid); processor.schedule(); } } /// A handle to a thread. pub struct Thread { pid: usize, mark: PhantomData, } impl Thread { /// Atomically makes the handle's token available if it is not already. pub fn unpark(&self) { let mut processor = S::processor(); processor.wakeup_(self.pid); } /// Gets the thread's unique identifier. pub fn id(&self) -> usize { self.pid } } /// An owned permission to join on a thread (block on its termination). pub struct JoinHandle { thread: Thread, mark: PhantomData, } impl JoinHandle { /// Extracts a handle to the underlying thread. pub fn thread(&self) -> &Thread { &self.thread } /// Waits for the associated thread to finish. pub fn join(self) -> Result { let mut processor = S::processor(); match processor.current_wait_for(self.thread.pid) { WaitResult::Ok(_, exit_code) => unsafe { Ok(*Box::from_raw(exit_code as *mut T)) } WaitResult::NotExist => Err(()), } } } //pub struct LocalKey { // init: fn() -> T, //} // //impl LocalKey { // pub fn with(&'static self, f: F) -> R // where F: FnOnce(&T) -> R // { // let map = unsafe { Self::get_map() }; // let key = self as *const _ as usize; // if !map.contains_key(&key) { // map.insert(key, Box::new((self.init)())); // } // let value = map.get(&key).unwrap().downcast_ref::().expect("type error"); // f(value) // } // pub const fn new(init: fn() -> T) -> Self { // LocalKey { init } // } // /// Get `BTreeMap>` at the current kernel stack bottom // /// The stack must be aligned with 0x8000 // unsafe fn get_map() -> &'static mut BTreeMap> { // const STACK_SIZE: usize = 0x8000; // let stack_var = 0usize; // let ptr = (&stack_var as *const _ as usize) / STACK_SIZE * STACK_SIZE; // let map = unsafe { &mut *(ptr as *mut Option>>) }; // if map.is_none() { // *map = Some(BTreeMap::new()); // } // map.as_mut().unwrap() // } //} // //pub mod test { // use thread; // use core::cell::RefCell; // use core::time::Duration; // // pub fn unpack() { // let parked_thread = thread::spawn(|| { // println!("Parking thread"); // thread::park(); // println!("Thread unparked"); // 5 // }); // // // Let some time pass for the thread to be spawned. // thread::sleep(Duration::from_secs(2)); // // println!("Unpark the thread"); // parked_thread.thread().unpark(); // // let ret = parked_thread.join().unwrap(); // assert_eq!(ret, 5); // } // // pub fn local_key() { // static FOO: thread::LocalKey> = thread::LocalKey::new(|| RefCell::new(1)); // // FOO.with(|f| { // assert_eq!(*f.borrow(), 1); // *f.borrow_mut() = 2; // }); // // // each thread starts out with the initial value of 1 // thread::spawn(move || { // FOO.with(|f| { // assert_eq!(*f.borrow(), 1); // *f.borrow_mut() = 3; // }); // }).join(); // // // we retain our original value of 2 despite the child thread // FOO.with(|f| { // assert_eq!(*f.borrow(), 2); // }); // println!("local key success"); // } //}