use boxed::FnBox; use ffi::CStr; use io; use time::Duration; use super::abi::usercalls; pub struct Thread(task_queue::JoinHandle); pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; mod task_queue { use sync::{Mutex, MutexGuard, Once}; use sync::mpsc; use boxed::FnBox; pub type JoinHandle = mpsc::Receiver<()>; pub(super) struct Task { p: Box, done: mpsc::Sender<()>, } impl Task { pub(super) fn new(p: Box) -> (Task, JoinHandle) { let (done, recv) = mpsc::channel(); (Task { p, done }, recv) } pub(super) fn run(self) { (self.p)(); let _ = self.done.send(()); } } static TASK_QUEUE_INIT: Once = Once::new(); static mut TASK_QUEUE: Option>> = None; pub(super) fn lock() -> MutexGuard<'static, Vec> { unsafe { TASK_QUEUE_INIT.call_once(|| TASK_QUEUE = Some(Default::default()) ); TASK_QUEUE.as_ref().unwrap().lock().unwrap() } } } impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements pub unsafe fn new(_stack: usize, p: Box) -> io::Result { let mut queue_lock = task_queue::lock(); usercalls::launch_thread()?; let (task, handle) = task_queue::Task::new(p); queue_lock.push(task); Ok(Thread(handle)) } pub(super) fn entry() { let mut guard = task_queue::lock(); let task = guard.pop().expect("Thread started but no tasks pending"); drop(guard); // make sure to not hold the task queue lock longer than necessary task.run() } pub fn yield_now() { assert_eq!( usercalls::wait(0, usercalls::raw::WAIT_NO).unwrap_err().kind(), io::ErrorKind::WouldBlock ); } pub fn set_name(_name: &CStr) { // FIXME: could store this pointer in TLS somewhere } pub fn sleep(_dur: Duration) { panic!("can't sleep"); // FIXME } pub fn join(self) { let _ = self.0.recv(); } } pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option { None } pub unsafe fn init() -> Option { None } }