Exclusive UPSafeCell: A RefCell wrapper
This commit is contained in:
parent
fd00e8de3a
commit
93ea7f9d4d
3 changed files with 26 additions and 20 deletions
|
@ -1,13 +1,15 @@
|
||||||
|
use core::cell::{RefCell, RefMut};
|
||||||
|
|
||||||
/// Wrap a static data structure inside it so that we are
|
/// Wrap a static data structure inside it so that we are
|
||||||
/// able to access it without any `unsafe`.
|
/// able to access it without any `unsafe`.
|
||||||
///
|
///
|
||||||
/// We should only use it in uniprocessor.
|
/// We should only use it in uniprocessor.
|
||||||
///
|
///
|
||||||
/// In order to get mutable reference of inner data, call
|
/// In order to get mutable reference of inner data, call
|
||||||
/// `upsafe_access`.
|
/// `exclusive_access`.
|
||||||
pub struct UPSafeCell<T> {
|
pub struct UPSafeCell<T> {
|
||||||
/// inner data
|
/// inner data
|
||||||
data: T,
|
inner: RefCell<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T> Sync for UPSafeCell<T> {}
|
unsafe impl<T> Sync for UPSafeCell<T> {}
|
||||||
|
@ -16,12 +18,10 @@ impl<T> UPSafeCell<T> {
|
||||||
/// User is responsible to guarantee that inner struct is only used in
|
/// User is responsible to guarantee that inner struct is only used in
|
||||||
/// uniprocessor.
|
/// uniprocessor.
|
||||||
pub unsafe fn new(value: T) -> Self {
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -46,33 +46,37 @@ lazy_static! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaskManager {
|
impl TaskManager {
|
||||||
fn run_first_task(&self) {
|
fn run_first_task(&self) -> ! {
|
||||||
let task0 = &mut self.inner.upsafe_access().tasks[0];
|
let mut inner = self.inner.exclusive_access();
|
||||||
|
let task0 = &mut inner.tasks[0];
|
||||||
task0.task_status = TaskStatus::Running;
|
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();
|
let mut _unused = TaskContext::zero_init();
|
||||||
|
// before this, we should drop local variables that must be dropped manually
|
||||||
unsafe {
|
unsafe {
|
||||||
__switch(
|
__switch(
|
||||||
&mut _unused as *mut TaskContext,
|
&mut _unused as *mut TaskContext,
|
||||||
next_task_cx_ptr,
|
next_task_cx_ptr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
panic!("unreachable in run_first_task!");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_current_suspended(&self) {
|
fn mark_current_suspended(&self) {
|
||||||
let mut inner = self.inner.upsafe_access();
|
let mut inner = self.inner.exclusive_access();
|
||||||
let current = inner.current_task;
|
let current = inner.current_task;
|
||||||
inner.tasks[current].task_status = TaskStatus::Ready;
|
inner.tasks[current].task_status = TaskStatus::Ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_current_exited(&self) {
|
fn mark_current_exited(&self) {
|
||||||
let mut inner = self.inner.upsafe_access();
|
let mut inner = self.inner.exclusive_access();
|
||||||
let current = inner.current_task;
|
let current = inner.current_task;
|
||||||
inner.tasks[current].task_status = TaskStatus::Exited;
|
inner.tasks[current].task_status = TaskStatus::Exited;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_next_task(&self) -> Option<usize> {
|
fn find_next_task(&self) -> Option<usize> {
|
||||||
let inner = self.inner.upsafe_access();
|
let inner = self.inner.exclusive_access();
|
||||||
let current = inner.current_task;
|
let current = inner.current_task;
|
||||||
(current + 1..current + self.num_app + 1)
|
(current + 1..current + self.num_app + 1)
|
||||||
.map(|id| id % self.num_app)
|
.map(|id| id % self.num_app)
|
||||||
|
@ -83,19 +87,21 @@ impl TaskManager {
|
||||||
|
|
||||||
fn run_next_task(&self) {
|
fn run_next_task(&self) {
|
||||||
if let Some(next) = self.find_next_task() {
|
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;
|
let current = inner.current_task;
|
||||||
inner.tasks[next].task_status = TaskStatus::Running;
|
inner.tasks[next].task_status = TaskStatus::Running;
|
||||||
inner.current_task = next;
|
inner.current_task = next;
|
||||||
let current_task_cx_ptr = &mut inner.tasks[current].task_cx as *mut TaskContext;
|
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;
|
let next_task_cx_ptr = &inner.tasks[next].task_cx as *const TaskContext;
|
||||||
drop(inner);
|
drop(inner);
|
||||||
|
// before this, we should drop local variables that must be dropped manually
|
||||||
unsafe {
|
unsafe {
|
||||||
__switch(
|
__switch(
|
||||||
current_task_cx_ptr,
|
current_task_cx_ptr,
|
||||||
next_task_cx_ptr,
|
next_task_cx_ptr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// go back to user mode
|
||||||
} else {
|
} else {
|
||||||
panic!("All applications completed!");
|
panic!("All applications completed!");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue