Add MutexBlocking.
This commit is contained in:
parent
8974a29245
commit
db6a93e60d
11 changed files with 119 additions and 13 deletions
|
@ -2,4 +2,4 @@ mod up;
|
|||
mod mutex;
|
||||
|
||||
pub use up::UPSafeCell;
|
||||
pub use mutex::{Mutex, MutexSpin};
|
||||
pub use mutex::{Mutex, MutexSpin, MutexBlocking};
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use super::UPSafeCell;
|
||||
use crate::task::suspend_current_and_run_next;
|
||||
use crate::task::{block_current_and_run_next, suspend_current_and_run_next};
|
||||
use crate::task::TaskControlBlock;
|
||||
use crate::task::{add_task, current_task};
|
||||
use alloc::{sync::Arc, collections::VecDeque};
|
||||
|
||||
pub trait Mutex: Sync + Send {
|
||||
fn lock(&self);
|
||||
|
@ -38,3 +41,47 @@ impl Mutex for MutexSpin {
|
|||
*locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MutexBlocking {
|
||||
inner: UPSafeCell<MutexBlockingInner>,
|
||||
}
|
||||
|
||||
pub struct MutexBlockingInner {
|
||||
locked: bool,
|
||||
wait_queue: VecDeque<Arc<TaskControlBlock>>,
|
||||
}
|
||||
|
||||
impl MutexBlocking {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: unsafe {
|
||||
UPSafeCell::new(MutexBlockingInner {
|
||||
locked: false,
|
||||
wait_queue: VecDeque::new(),
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mutex for MutexBlocking {
|
||||
fn lock(&self) {
|
||||
let mut mutex_inner = self.inner.exclusive_access();
|
||||
if mutex_inner.locked {
|
||||
mutex_inner.wait_queue.push_back(current_task().unwrap());
|
||||
drop(mutex_inner);
|
||||
block_current_and_run_next();
|
||||
} else {
|
||||
mutex_inner.locked = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn unlock(&self) {
|
||||
let mut mutex_inner = self.inner.exclusive_access();
|
||||
assert_eq!(mutex_inner.locked, true);
|
||||
mutex_inner.locked = false;
|
||||
if let Some(waking_task) = mutex_inner.wait_queue.pop_front() {
|
||||
add_task(waking_task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
|||
SYSCALL_THREAD_CREATE => sys_thread_create(args[0]),
|
||||
SYSCALL_GETTID => sys_gettid(),
|
||||
SYSCALL_WAITTID => sys_waittid(args[0]) as isize,
|
||||
SYSCALL_MUTEX_CREATE => sys_mutex_create(),
|
||||
SYSCALL_MUTEX_CREATE => sys_mutex_create(args[0] == 1),
|
||||
SYSCALL_MUTEX_LOCK => sys_mutex_lock(args[0]),
|
||||
SYSCALL_MUTEX_UNLOCK => sys_mutex_unlock(args[0]),
|
||||
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::task::current_process;
|
||||
use crate::sync::MutexSpin;
|
||||
use crate::sync::{MutexSpin, MutexBlocking};
|
||||
use alloc::sync::Arc;
|
||||
|
||||
pub fn sys_mutex_create() -> isize {
|
||||
pub fn sys_mutex_create(blocking: bool) -> isize {
|
||||
let process = current_process();
|
||||
let mut process_inner = process.inner_exclusive_access();
|
||||
if let Some(id) = process_inner
|
||||
|
@ -11,7 +11,11 @@ pub fn sys_mutex_create() -> isize {
|
|||
.enumerate()
|
||||
.find(|(_, item)| item.is_none())
|
||||
.map(|(id, _)| id) {
|
||||
process_inner.mutex_list[id] = Some(Arc::new(MutexSpin::new()));
|
||||
process_inner.mutex_list[id] = if !blocking {
|
||||
Some(Arc::new(MutexSpin::new()))
|
||||
} else {
|
||||
Some(Arc::new(MutexBlocking::new()))
|
||||
};
|
||||
id as isize
|
||||
} else {
|
||||
process_inner.mutex_list.push(Some(Arc::new(MutexSpin::new())));
|
||||
|
|
|
@ -52,6 +52,15 @@ pub fn suspend_current_and_run_next() {
|
|||
schedule(task_cx_ptr);
|
||||
}
|
||||
|
||||
pub fn block_current_and_run_next() {
|
||||
let task = take_current_task().unwrap();
|
||||
let mut task_inner = task.inner_exclusive_access();
|
||||
let task_cx_ptr = &mut task_inner.task_cx as *mut TaskContext;
|
||||
task_inner.task_status = TaskStatus::Blocking;
|
||||
drop(task_inner);
|
||||
schedule(task_cx_ptr);
|
||||
}
|
||||
|
||||
pub fn exit_current_and_run_next(exit_code: i32) {
|
||||
let task = take_current_task().unwrap();
|
||||
let mut task_inner = task.inner_exclusive_access();
|
||||
|
|
|
@ -74,4 +74,5 @@ impl TaskControlBlock {
|
|||
pub enum TaskStatus {
|
||||
Ready,
|
||||
Running,
|
||||
Blocking,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue