fix thread crate example

toolchain_update
WangRunji 6 years ago
parent cc6a069586
commit 7eaeb4711e

@ -3,7 +3,6 @@
#![feature(asm)] #![feature(asm)]
#![feature(alloc)] #![feature(alloc)]
#![feature(naked_functions)] #![feature(naked_functions)]
#![feature(panic_info_message)]
#![feature(lang_items)] #![feature(lang_items)]
extern crate alloc; extern crate alloc;
@ -33,21 +32,26 @@ pub extern "C" fn _start() -> ! {
// init heap // init heap
unsafe { HEAP_ALLOCATOR.lock().init(HEAP.as_ptr() as usize, HEAP_SIZE); } unsafe { HEAP_ALLOCATOR.lock().init(HEAP.as_ptr() as usize, HEAP_SIZE); }
// init processor // init processor
let scheduler = Box::new(scheduler::RRScheduler::new(5)); let scheduler = scheduler::RRScheduler::new(5);
let thread_pool = Arc::new(ThreadPool::new(scheduler, MAX_PROC_NUM)); let thread_pool = Arc::new(ThreadPool::new(scheduler, MAX_PROC_NUM));
unsafe { processor().init(0, Thread::init(), thread_pool); } unsafe { processor().init(0, Thread::init(), thread_pool); }
// init threads // init threads
thread::spawn(|| { thread::spawn(|| {
let tid = processor().tid(); let tid = processor().tid();
serial_println!("I'm thread {}! yield...", tid); serial_println!("[{}] yield", tid);
thread::yield_now(); thread::yield_now();
serial_println!("I'm thread {}! exit...", tid); serial_println!("[{}] spawn", tid);
}); let t2 = thread::spawn(|| {
thread::spawn(|| {
let tid = processor().tid(); let tid = processor().tid();
serial_println!("I'm thread {}! yield...", tid); serial_println!("[{}] yield", tid);
thread::yield_now(); thread::yield_now();
serial_println!("I'm thread {}! exit...", tid); serial_println!("[{}] return 8", tid);
8
});
serial_println!("[{}] join", tid);
let ret = t2.join();
serial_println!("[{}] get {:?}", tid, ret);
serial_println!("[{}] exit", tid);
}); });
// run threads // run threads
processor().run(); processor().run();
@ -158,6 +162,9 @@ impl Context for Thread {
: : : : "intel" "volatile" ) : : : : "intel" "volatile" )
} }
} }
fn set_tid(&mut self, _tid: usize) {
}
} }
/// Define global `Processor` for each core. /// Define global `Processor` for each core.
@ -180,9 +187,7 @@ pub fn new_kernel_context(entry: extern fn(usize) -> !, arg0: usize) -> Box<Cont
#[panic_handler] #[panic_handler]
fn panic(info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {
let location = info.location().unwrap(); serial_println!("\n{}", info);
let message = info.message().unwrap();
serial_println!("\nPANIC @ {}\n\t{}", location, message);
unsafe { exit_qemu(); } unsafe { exit_qemu(); }
loop {} loop {}

@ -143,16 +143,11 @@ impl<T> JoinHandle<T> {
/// 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, ()> {
loop { loop {
trace!("join thread {}", self.thread.tid); trace!("try to join thread {}", self.thread.tid);
match processor().manager().get_status(self.thread.tid) { if let Some(exit_code) = processor().manager().try_remove(self.thread.tid) {
Some(Status::Exited(exit_code)) => {
processor().manager().remove(self.thread.tid);
// Find return value on the heap from the exit code. // Find return value on the heap from the exit code.
return Ok(unsafe { *Box::from_raw(exit_code as *mut T) }); return Ok(unsafe { *Box::from_raw(exit_code as *mut T) });
} }
None => return Err(()),
_ => {}
}
processor().manager().wait(current().id(), self.thread.tid); processor().manager().wait(current().id(), self.thread.tid);
processor().yield_now(); processor().yield_now();
} }

@ -59,7 +59,7 @@ impl ThreadPool {
return (i, thread); return (i, thread);
} }
} }
panic!("Process number exceeded"); panic!("Thread number exceeded");
} }
/// Add a new thread /// Add a new thread
@ -77,7 +77,7 @@ impl ThreadPool {
tid tid
} }
/// Make process `tid` time slice -= 1. /// Make thread `tid` time slice -= 1.
/// Return true if time slice == 0. /// Return true if time slice == 0.
/// Called by timer interrupt handler. /// Called by timer interrupt handler.
pub(crate) fn tick(&self, cpu_id: usize, tid: Option<Tid>) -> bool { pub(crate) fn tick(&self, cpu_id: usize, tid: Option<Tid>) -> bool {
@ -96,35 +96,35 @@ impl ThreadPool {
} }
} }
/// Set the priority of process `tid` /// Set the priority of thread `tid`
pub fn set_priority(&self, tid: Tid, priority: u8) { pub fn set_priority(&self, tid: Tid, priority: u8) {
self.scheduler.set_priority(tid, priority); self.scheduler.set_priority(tid, priority);
} }
/// Called by Processor to get a process to run. /// Called by Processor to get a thread to run.
/// The manager first mark it `Running`, /// The manager first mark it `Running`,
/// then take out and return its Context. /// then take out and return its Context.
pub(crate) fn run(&self, cpu_id: usize) -> Option<(Tid, Box<Context>)> { pub(crate) fn run(&self, cpu_id: usize) -> Option<(Tid, Box<Context>)> {
self.scheduler.pop(cpu_id) self.scheduler.pop(cpu_id)
.map(|tid| { .map(|tid| {
let mut proc_lock = self.threads[tid].lock(); let mut proc_lock = self.threads[tid].lock();
let mut proc = proc_lock.as_mut().expect("process not exist"); let mut proc = proc_lock.as_mut().expect("thread not exist");
proc.status = Status::Running(cpu_id); proc.status = Status::Running(cpu_id);
(tid, proc.context.take().expect("context not exist")) (tid, proc.context.take().expect("context not exist"))
}) })
} }
/// Called by Processor to finish running a process /// Called by Processor to finish running a thread
/// and give its context back. /// and give its context back.
pub(crate) fn stop(&self, tid: Tid, context: Box<Context>) { pub(crate) fn stop(&self, tid: Tid, context: Box<Context>) {
let mut proc_lock = self.threads[tid].lock(); let mut proc_lock = self.threads[tid].lock();
let mut proc = proc_lock.as_mut().expect("process not exist"); let proc = proc_lock.as_mut().expect("thread not exist");
proc.status = proc.status_after_stop.clone(); proc.status = proc.status_after_stop.clone();
proc.status_after_stop = Status::Ready; proc.status_after_stop = Status::Ready;
proc.context = Some(context); proc.context = Some(context);
match proc.status { match proc.status {
Status::Ready => self.scheduler.push(tid), Status::Ready => self.scheduler.push(tid),
Status::Exited(_) => self.exit_handler(tid, proc), Status::Exited(_) => self.exit_handler(proc),
_ => {} _ => {}
} }
} }
@ -135,22 +135,22 @@ impl ThreadPool {
pub(crate) fn wait(&self, tid: Tid, target: Tid) { pub(crate) fn wait(&self, tid: Tid, target: Tid) {
self.set_status(tid, Status::Sleeping); self.set_status(tid, Status::Sleeping);
let mut target_lock = self.threads[target].lock(); let mut target_lock = self.threads[target].lock();
let target = target_lock.as_mut().expect("process not exist"); let target = target_lock.as_mut().expect("thread not exist");
target.waiter = Some(tid); target.waiter = Some(tid);
} }
/// Switch the status of a process. /// Switch the status of a thread.
/// 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) {
let mut proc_lock = self.threads[tid].lock(); let mut proc_lock = self.threads[tid].lock();
if let Some(mut proc) = proc_lock.as_mut() { if let Some(mut proc) = proc_lock.as_mut() {
trace!("process {} {:?} -> {:?}", tid, proc.status, status); trace!("thread {} {:?} -> {:?}", tid, proc.status, status);
match (&proc.status, &status) { match (&proc.status, &status) {
(Status::Ready, Status::Ready) => return, (Status::Ready, Status::Ready) => return,
(Status::Ready, _) => panic!("can not remove a process from ready queue"), (Status::Ready, _) => panic!("can not remove a thread from ready queue"),
(Status::Exited(_), _) => panic!("can not set status for a exited thread"), (Status::Exited(_), _) => panic!("can not set status for a exited thread"),
(Status::Sleeping, Status::Exited(_)) => self.timer.lock().stop(Event::Wakeup(tid)), (Status::Sleeping, Status::Exited(_)) => self.timer.lock().stop(Event::Wakeup(tid)),
(Status::Running(_), Status::Ready) => {} // process will be added to scheduler in stop() (Status::Running(_), Status::Ready) => {} // thread will be added to scheduler in stop()
(_, Status::Ready) => self.scheduler.push(tid), (_, Status::Ready) => self.scheduler.push(tid),
_ => {} _ => {}
} }
@ -159,30 +159,25 @@ impl ThreadPool {
_ => proc.status = status, _ => proc.status = status,
} }
match proc.status { match proc.status {
Status::Exited(_) => self.exit_handler(tid, proc), Status::Exited(_) => self.exit_handler(proc),
_ => {} _ => {}
} }
} }
} }
pub fn get_status(&self, tid: Tid) -> Option<Status> { /// Try to remove an exited thread `tid`.
if tid < self.threads.len() { /// Return its exit code if success.
self.threads[tid].lock().as_ref().map(|p| p.status.clone()) pub fn try_remove(&self, tid: Tid) -> Option<ExitCode> {
} else {
None
}
}
/// Remove an exited proc `tid`.
pub fn remove(&self, tid: Tid) {
let mut proc_lock = self.threads[tid].lock(); let mut proc_lock = self.threads[tid].lock();
let proc = proc_lock.as_ref().expect("process not exist"); let proc = proc_lock.as_ref().expect("thread not exist");
match proc.status { match proc.status {
Status::Exited(_) => {} Status::Exited(code) => {
_ => panic!("can not remove non-exited process"),
}
// release the tid // release the tid
*proc_lock = None; *proc_lock = None;
Some(code)
},
_ => None,
}
} }
/// Sleep `tid` for `time` ticks. /// Sleep `tid` for `time` ticks.
@ -203,7 +198,7 @@ impl ThreadPool {
self.set_status(tid, Status::Exited(code)); self.set_status(tid, Status::Exited(code));
} }
/// Called when a thread exit /// Called when a thread exit
fn exit_handler(&self, _tid: Tid, proc: &mut Thread) { fn exit_handler(&self, proc: &mut Thread) {
// wake up waiter // wake up waiter
if let Some(waiter) = proc.waiter { if let Some(waiter) = proc.waiter {
self.wakeup(waiter); self.wakeup(waiter);

Loading…
Cancel
Save