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.
pub fn current() -> 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, T>(f: F) -> JoinHandle<T>
let f = unsafe { Box::from_raw(f as *mut F) };
// 调用f并将其返回值也放在堆上
let ret = Box::new(f());
// 清理本地线程存储
// unsafe { LocalKey::<usize>::get_map() }.clear();
// 让Processor退出当前线程
// 把f返回值在堆上的指针以线程返回码的形式传递出去
let exit_code = Box::into_raw(ret) as usize;
@ -97,6 +95,7 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
// 接下来看看`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<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, ()> {
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 {
status: Status,
status_after_stop: Status,
waiter: Option<Tid>,
context: Option<Box<Context>>,
}
@ -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;
}

Loading…
Cancel
Save