From 2bd7dcf044ccabcab83bfb8351e6cfa9f5e0d8f8 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Mon, 19 Jul 2021 23:56:32 +0800 Subject: [PATCH] Exclusive UPSafeCell: A RefCell wrapper --- os/src/main.rs | 2 +- os/src/sync/up.rs | 20 ++++++++++---------- os/src/task/mod.rs | 24 +++++++++++++++--------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/os/src/main.rs b/os/src/main.rs index fbd6fff6..4689f03d 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -26,7 +26,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 a4778651..66c8a796 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -27,12 +27,12 @@ lazy_static! { let mut tasks = [ TaskControlBlock { task_cx: TaskContext::zero_init(), - task_status: TaskStatus::UnInit + task_status: TaskStatus::UnInit }; MAX_APP_NUM ]; for i in 0..num_app { - tasks[i].task_cx = TaskContext::goto_restore(init_app_cx(i)); + tasks[i].task_cx = TaskContext::goto_restore(init_app_cx(i)); tasks[i].task_status = TaskStatus::Ready; } TaskManager { @@ -46,33 +46,37 @@ lazy_static! { } impl TaskManager { - fn run_first_task(&self) { - let task0 = &mut self.inner.upsafe_access().tasks[0]; + fn run_first_task(&self) -> ! { + let mut inner = self.inner.exclusive_access(); + let task0 = &mut inner.tasks[0]; task0.task_status = TaskStatus::Running; - let next_task_cx_ptr = &task0.task_cx as *const TaskContext; + let next_task_cx_ptr = &task0.task_cx as *const TaskContext; + 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 TaskContext, next_task_cx_ptr, ); } + panic!("unreachable in run_first_task!"); } fn mark_current_suspended(&self) { - let mut inner = self.inner.upsafe_access(); + let mut inner = self.inner.exclusive_access(); let current = inner.current_task; inner.tasks[current].task_status = TaskStatus::Ready; } fn mark_current_exited(&self) { - let mut inner = self.inner.upsafe_access(); + let mut inner = self.inner.exclusive_access(); let current = inner.current_task; inner.tasks[current].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) @@ -83,19 +87,21 @@ impl TaskManager { 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!"); } -- GitLab