recover thread join

master
WangRunji 6 years ago
parent 8cb11b7aa8
commit d64681a26b

@ -30,7 +30,7 @@ fn new_kernel_context(_entry: extern fn(usize) -> !, _arg: usize) -> Box<Context
/// Gets a handle to the thread that invokes it. /// Gets a handle to the thread that invokes it.
pub fn current() -> Thread { pub fn current() -> Thread {
Thread { pid: processor().tid() } Thread { tid: processor().tid() }
} }
/// Puts the current thread to sleep for the specified amount of time. /// Puts the current thread to sleep for the specified amount of time.
@ -79,8 +79,6 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
let f = unsafe { Box::from_raw(f as *mut F) }; let f = unsafe { Box::from_raw(f as *mut F) };
// 调用f并将其返回值也放在堆上 // 调用f并将其返回值也放在堆上
let ret = Box::new(f()); let ret = Box::new(f());
// 清理本地线程存储
// unsafe { LocalKey::<usize>::get_map() }.clear();
// 让Processor退出当前线程 // 让Processor退出当前线程
// 把f返回值在堆上的指针以线程返回码的形式传递出去 // 把f返回值在堆上的指针以线程返回码的形式传递出去
let exit_code = Box::into_raw(ret) as usize; let exit_code = Box::into_raw(ret) as usize;
@ -97,6 +95,7 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
// 接下来看看`JoinHandle::join()`的实现 // 接下来看看`JoinHandle::join()`的实现
// 了解是如何获取f返回值的 // 了解是如何获取f返回值的
return JoinHandle { return JoinHandle {
thread: Thread { tid },
mark: PhantomData, mark: PhantomData,
}; };
} }
@ -116,28 +115,46 @@ pub fn park() {
/// A handle to a thread. /// A handle to a thread.
pub struct Thread { pub struct Thread {
pid: usize, tid: usize,
} }
impl Thread { impl Thread {
/// Atomically makes the handle's token available if it is not already. /// Atomically makes the handle's token available if it is not already.
pub fn unpark(&self) { pub fn unpark(&self) {
processor().manager().wakeup(self.pid); processor().manager().wakeup(self.tid);
} }
/// Gets the thread's unique identifier. /// Gets the thread's unique identifier.
pub fn id(&self) -> usize { 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<T> { pub struct JoinHandle<T> {
thread: Thread,
mark: PhantomData<T>, mark: PhantomData<T>,
} }
impl<T> JoinHandle<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. /// Waits for the associated thread to finish.
pub fn join(self) -> Result<T, ()> { pub fn join(self) -> Result<T, ()> {
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();
}
} }
} }

@ -8,6 +8,7 @@ use crate::timer::Timer;
struct Thread { struct Thread {
status: Status, status: Status,
status_after_stop: Status, status_after_stop: Status,
waiter: Option<Tid>,
context: Option<Box<Context>>, context: Option<Box<Context>>,
} }
@ -69,6 +70,7 @@ impl ThreadPool {
*thread = Some(Thread { *thread = Some(Thread {
status: Status::Ready, status: Status::Ready,
status_after_stop: Status::Ready, status_after_stop: Status::Ready,
waiter: None,
context: Some(context), context: Some(context),
}); });
self.scheduler.push(tid); 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. /// Switch the status of a process.
/// Insert/Remove it to/from scheduler if necessary. /// Insert/Remove it to/from scheduler if necessary.
fn set_status(&self, tid: Tid, status: Status) { fn set_status(&self, tid: Tid, status: Status) {
@ -190,8 +202,12 @@ impl ThreadPool {
// NOTE: if `tid` is running, status change will be deferred. // NOTE: if `tid` is running, status change will be deferred.
self.set_status(tid, Status::Exited(code)); 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) { fn exit_handler(&self, tid: Tid, proc: &mut Thread) {
// wake up waiter
if let Some(waiter) = proc.waiter {
self.wakeup(waiter);
}
// drop its context // drop its context
proc.context = None; proc.context = None;
} }

Loading…
Cancel
Save