diff --git a/crate/thread/src/std_thread.rs b/crate/thread/src/std_thread.rs index 5cbceb0..1b35f67 100644 --- a/crate/thread/src/std_thread.rs +++ b/crate/thread/src/std_thread.rs @@ -30,7 +30,7 @@ fn new_kernel_context(_entry: extern fn(usize) -> !, _arg: usize) -> Box Thread { - Thread { pid: processor().tid() } + Thread { tid: processor().tid() } } /// Puts the current thread to sleep for the specified amount of time. @@ -79,8 +79,6 @@ pub fn spawn(f: F) -> JoinHandle let f = unsafe { Box::from_raw(f as *mut F) }; // 调用f,并将其返回值也放在堆上 let ret = Box::new(f()); - // 清理本地线程存储 - // unsafe { LocalKey::::get_map() }.clear(); // 让Processor退出当前线程 // 把f返回值在堆上的指针,以线程返回码的形式传递出去 let exit_code = Box::into_raw(ret) as usize; @@ -97,6 +95,7 @@ pub fn spawn(f: F) -> JoinHandle // 接下来看看`JoinHandle::join()`的实现 // 了解是如何获取f返回值的 return JoinHandle { + thread: Thread { tid }, mark: PhantomData, }; } @@ -116,28 +115,46 @@ pub fn park() { /// A handle to a thread. pub struct Thread { - pid: usize, + tid: usize, } impl Thread { /// Atomically makes the handle's token available if it is not already. pub fn unpark(&self) { - processor().manager().wakeup(self.pid); + processor().manager().wakeup(self.tid); } /// Gets the thread's unique identifier. pub fn id(&self) -> usize { - self.pid + self.tid } } -/// An owned permission to join on a process (block on its termination). +/// 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 { - unimplemented!(); + loop { + trace!("join thread {}", self.thread.tid); + match processor().manager().get_status(self.thread.tid) { + Some(Status::Exited(exit_code)) => { + processor().manager().remove(self.thread.tid); + // Find return value on the heap from the exit code. + return Ok(unsafe { *Box::from_raw(exit_code as *mut T) }); + } + None => return Err(()), + _ => {} + } + processor().manager().wait(current().id(), self.thread.tid); + processor().yield_now(); + } } -} \ No newline at end of file +} diff --git a/crate/thread/src/thread_pool.rs b/crate/thread/src/thread_pool.rs index 87fa627..2b61935 100644 --- a/crate/thread/src/thread_pool.rs +++ b/crate/thread/src/thread_pool.rs @@ -8,6 +8,7 @@ use crate::timer::Timer; struct Thread { status: Status, status_after_stop: Status, + waiter: Option, context: Option>, } @@ -69,6 +70,7 @@ impl ThreadPool { *thread = Some(Thread { status: Status::Ready, status_after_stop: Status::Ready, + waiter: None, context: Some(context), }); self.scheduler.push(tid); @@ -127,6 +129,16 @@ impl ThreadPool { } } + /// Called by `JoinHandle` to let thread `tid` wait for `target`. + /// The `tid` is going to sleep, and will be woke up when `target` exit. + /// (see `exit_handler()`) + pub(crate) fn wait(&self, tid: Tid, target: Tid) { + self.set_status(tid, Status::Sleeping); + let mut target_lock = self.threads[target].lock(); + let target = target_lock.as_mut().expect("process not exist"); + target.waiter = Some(tid); + } + /// Switch the status of a process. /// Insert/Remove it to/from scheduler if necessary. fn set_status(&self, tid: Tid, status: Status) { @@ -190,8 +202,12 @@ impl ThreadPool { // NOTE: if `tid` is running, status change will be deferred. self.set_status(tid, Status::Exited(code)); } - /// Called when a process exit + /// Called when a thread exit fn exit_handler(&self, tid: Tid, proc: &mut Thread) { + // wake up waiter + if let Some(waiter) = proc.waiter { + self.wakeup(waiter); + } // drop its context proc.context = None; }