parent
dcdbcfbce8
commit
2ad61cae65
@ -0,0 +1,135 @@
|
|||||||
|
//! Thread std-like interface
|
||||||
|
//!
|
||||||
|
//! Based on process mod.
|
||||||
|
//! Used in the kernel.
|
||||||
|
|
||||||
|
use process::*;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::ptr;
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
|
/// Gets a handle to the thread that invokes it.
|
||||||
|
pub fn current() -> Thread {
|
||||||
|
Thread {
|
||||||
|
pid: PROCESSOR.try().unwrap().lock().current_pid(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Puts the current thread to sleep for the specified amount of time.
|
||||||
|
pub fn sleep(time: usize) {
|
||||||
|
// TODO: use core::time::Duration
|
||||||
|
info!("sleep: {} ticks", time);
|
||||||
|
let mut processor = PROCESSOR.try().unwrap().lock();
|
||||||
|
let pid = processor.current_pid();
|
||||||
|
processor.sleep(pid, time);
|
||||||
|
processor.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Spawns a new thread, returning a JoinHandle for it.
|
||||||
|
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
|
||||||
|
where
|
||||||
|
F: Send + 'static + FnOnce() -> T,
|
||||||
|
T: Send + 'static,
|
||||||
|
{
|
||||||
|
use process;
|
||||||
|
let pid = process::add_kernel_process(kernel_thread_entry::<F, T>, &f as *const _ as usize);
|
||||||
|
return JoinHandle {
|
||||||
|
thread: Thread { pid },
|
||||||
|
mark: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern fn kernel_thread_entry<F, T>(f: usize) -> !
|
||||||
|
where
|
||||||
|
F: Send + 'static + FnOnce() -> T,
|
||||||
|
T: Send + 'static,
|
||||||
|
{
|
||||||
|
debug!("kernel_thread_entry");
|
||||||
|
let f = unsafe { ptr::read(f as *mut F) };
|
||||||
|
let ret = Box::new(f());
|
||||||
|
let mut processor = PROCESSOR.try().unwrap().lock();
|
||||||
|
let pid = processor.current_pid();
|
||||||
|
processor.exit(pid, Box::into_raw(ret) as usize);
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cooperatively gives up a timeslice to the OS scheduler.
|
||||||
|
pub fn yield_now() {
|
||||||
|
info!("yield:");
|
||||||
|
let mut processor = PROCESSOR.try().unwrap().lock();
|
||||||
|
processor.set_reschedule();
|
||||||
|
processor.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blocks unless or until the current thread's token is made available.
|
||||||
|
pub fn park() {
|
||||||
|
let mut processor = PROCESSOR.try().unwrap().lock();
|
||||||
|
let pid = processor.current_pid();
|
||||||
|
processor.sleep_(pid);
|
||||||
|
processor.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A handle to a thread.
|
||||||
|
pub struct Thread {
|
||||||
|
pid: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Thread {
|
||||||
|
/// Atomically makes the handle's token available if it is not already.
|
||||||
|
pub fn unpark(&self) {
|
||||||
|
let mut processor = PROCESSOR.try().unwrap().lock();
|
||||||
|
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<T> {
|
||||||
|
thread: Thread,
|
||||||
|
mark: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> JoinHandle<T> {
|
||||||
|
/// 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<T, ()> {
|
||||||
|
let mut processor = PROCESSOR.try().unwrap().lock();
|
||||||
|
match processor.current_wait_for(self.thread.pid) {
|
||||||
|
WaitResult::Ok(_, exit_code) => {
|
||||||
|
unsafe {
|
||||||
|
let value = Box::from_raw(exit_code as *mut T);
|
||||||
|
Ok(ptr::read(exit_code as *const T))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WaitResult::NotExist => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod test {
|
||||||
|
use thread;
|
||||||
|
|
||||||
|
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(200);
|
||||||
|
|
||||||
|
println!("Unpark the thread");
|
||||||
|
parked_thread.thread().unpark();
|
||||||
|
|
||||||
|
let ret = parked_thread.join().unwrap();
|
||||||
|
assert_eq!(ret, 5);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue