diff --git a/os/src/main.rs b/os/src/main.rs index 14eb9542..02e62a08 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -33,7 +33,7 @@ fn clear_bss() { } unsafe { core::slice::from_raw_parts_mut( - sbss as usize as *mut u8, + sbss as usize as *mut u8, ebss as usize - sbss as usize, ).fill(0); } diff --git a/os/src/sync/up.rs b/os/src/sync/up.rs index 849ac4bc..642668c1 100644 --- a/os/src/sync/up.rs +++ b/os/src/sync/up.rs @@ -1,13 +1,15 @@ -/// Wrap a static data structure inside it so that we are +use core::cell::{RefCell, RefMut}; + +/// Wrap a static data structure inside it so that we are /// able to access it without any `unsafe`. /// /// We should only use it in uniprocessor. /// -/// In order to get mutable reference of inner data, call -/// `upsafe_access`. +/// In order to get mutable reference of inner data, call +/// `exclusive_access`. pub struct UPSafeCell { /// inner data - data: T, + inner: RefCell, } unsafe impl Sync for UPSafeCell {} @@ -16,12 +18,10 @@ impl UPSafeCell { /// User is responsible to guarantee that inner struct is only used in /// uniprocessor. pub unsafe fn new(value: T) -> Self { - Self { data: value, } + Self { inner: RefCell::new(value) } } - /// Mention that user should hold exactly one &mut T at a time. - pub fn upsafe_access(&self) -> &mut T { - unsafe { - &mut *(&self.data as *const _ as usize as *mut T) - } + /// Panic if the data has been borrowed. + pub fn exclusive_access(&self) -> RefMut<'_, T> { + self.inner.borrow_mut() } } \ No newline at end of file diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 56eb239d..5a85eebd 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -45,32 +45,37 @@ lazy_static! { } impl TaskManager { - fn run_first_task(&self) { - let next_task = &mut self.inner.upsafe_access().tasks[0]; + fn run_first_task(&self) -> ! { + let mut inner = self.inner.exclusive_access(); + let next_task = &mut inner.tasks[0]; next_task.task_status = TaskStatus::Running; let next_task_cx_ptr = &next_task.task_cx as *const TaskContext; - drop(next_task); + drop(inner); let mut _unused = TaskContext::zero_init(); + // before this, we should drop local variables that must be dropped manually unsafe { __switch( &mut _unused as *mut _, next_task_cx_ptr, ); } + panic!("unreachable in run_first_task!"); } fn mark_current_suspended(&self) { - let inner = self.inner.upsafe_access(); - inner.tasks[inner.current_task].task_status = TaskStatus::Ready; + let mut inner = self.inner.exclusive_access(); + let cur = inner.current_task; + inner.tasks[cur].task_status = TaskStatus::Ready; } fn mark_current_exited(&self) { - let inner = self.inner.upsafe_access(); - inner.tasks[inner.current_task].task_status = TaskStatus::Exited; + let mut inner = self.inner.exclusive_access(); + let cur = inner.current_task; + inner.tasks[cur].task_status = TaskStatus::Exited; } fn find_next_task(&self) -> Option { - let inner = self.inner.upsafe_access(); + let inner = self.inner.exclusive_access(); let current = inner.current_task; (current + 1..current + self.num_app + 1) .map(|id| id % self.num_app) @@ -80,30 +85,32 @@ impl TaskManager { } fn get_current_token(&self) -> usize { - let inner = self.inner.upsafe_access(); + let inner = self.inner.exclusive_access(); inner.tasks[inner.current_task].get_user_token() } fn get_current_trap_cx(&self) -> &mut TrapContext { - let inner = self.inner.upsafe_access(); + let inner = self.inner.exclusive_access(); inner.tasks[inner.current_task].get_trap_cx() } fn run_next_task(&self) { if let Some(next) = self.find_next_task() { - let mut inner = self.inner.upsafe_access(); + let mut inner = self.inner.exclusive_access(); let current = inner.current_task; inner.tasks[next].task_status = TaskStatus::Running; inner.current_task = next; let current_task_cx_ptr = &mut inner.tasks[current].task_cx as *mut TaskContext; let next_task_cx_ptr = &inner.tasks[next].task_cx as *const TaskContext; drop(inner); + // before this, we should drop local variables that must be dropped manually unsafe { __switch( current_task_cx_ptr, next_task_cx_ptr, ); } + // go back to user mode } else { panic!("All applications completed!"); }