mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 09:26:26 +04:00
Add MutexBlocking.
This commit is contained in:
parent
b0fad5aca3
commit
7225254d8a
@ -2,4 +2,4 @@ mod up;
|
|||||||
mod mutex;
|
mod mutex;
|
||||||
|
|
||||||
pub use up::UPSafeCell;
|
pub use up::UPSafeCell;
|
||||||
pub use mutex::{Mutex, MutexSpin};
|
pub use mutex::{Mutex, MutexSpin, MutexBlocking};
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use super::UPSafeCell;
|
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 {
|
pub trait Mutex: Sync + Send {
|
||||||
fn lock(&self);
|
fn lock(&self);
|
||||||
@ -38,3 +41,47 @@ impl Mutex for MutexSpin {
|
|||||||
*locked = false;
|
*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_THREAD_CREATE => sys_thread_create(args[0]),
|
||||||
SYSCALL_GETTID => sys_gettid(),
|
SYSCALL_GETTID => sys_gettid(),
|
||||||
SYSCALL_WAITTID => sys_waittid(args[0]) as isize,
|
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_LOCK => sys_mutex_lock(args[0]),
|
||||||
SYSCALL_MUTEX_UNLOCK => sys_mutex_unlock(args[0]),
|
SYSCALL_MUTEX_UNLOCK => sys_mutex_unlock(args[0]),
|
||||||
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::task::current_process;
|
use crate::task::current_process;
|
||||||
use crate::sync::MutexSpin;
|
use crate::sync::{MutexSpin, MutexBlocking};
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
pub fn sys_mutex_create() -> isize {
|
pub fn sys_mutex_create(blocking: bool) -> isize {
|
||||||
let process = current_process();
|
let process = current_process();
|
||||||
let mut process_inner = process.inner_exclusive_access();
|
let mut process_inner = process.inner_exclusive_access();
|
||||||
if let Some(id) = process_inner
|
if let Some(id) = process_inner
|
||||||
@ -11,7 +11,11 @@ pub fn sys_mutex_create() -> isize {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, item)| item.is_none())
|
.find(|(_, item)| item.is_none())
|
||||||
.map(|(id, _)| id) {
|
.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
|
id as isize
|
||||||
} else {
|
} else {
|
||||||
process_inner.mutex_list.push(Some(Arc::new(MutexSpin::new())));
|
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);
|
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) {
|
pub fn exit_current_and_run_next(exit_code: i32) {
|
||||||
let task = take_current_task().unwrap();
|
let task = take_current_task().unwrap();
|
||||||
let mut task_inner = task.inner_exclusive_access();
|
let mut task_inner = task.inner_exclusive_access();
|
||||||
|
@ -74,4 +74,5 @@ impl TaskControlBlock {
|
|||||||
pub enum TaskStatus {
|
pub enum TaskStatus {
|
||||||
Ready,
|
Ready,
|
||||||
Running,
|
Running,
|
||||||
|
Blocking,
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ use user_lib::{exit, thread_create, waittid, get_time};
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
const PER_THREAD: usize = 10000;
|
const PER_THREAD: usize = 1000;
|
||||||
const THREAD_COUNT: usize = 8;
|
const THREAD_COUNT: usize = 16;
|
||||||
|
|
||||||
unsafe fn f() -> ! {
|
unsafe fn f() -> ! {
|
||||||
let mut t = 2usize;
|
let mut t = 2usize;
|
||||||
|
44
user/src/bin/race_adder_mutex_blocking.rs
Normal file
44
user/src/bin/race_adder_mutex_blocking.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate user_lib;
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use user_lib::{exit, thread_create, waittid, get_time};
|
||||||
|
use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock};
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
static mut A: usize = 0;
|
||||||
|
const PER_THREAD: usize = 10000;
|
||||||
|
const THREAD_COUNT: usize = 8;
|
||||||
|
|
||||||
|
unsafe fn f() -> ! {
|
||||||
|
let mut t = 2usize;
|
||||||
|
for _ in 0..PER_THREAD {
|
||||||
|
mutex_lock(0);
|
||||||
|
let a = &mut A as *mut usize;
|
||||||
|
let cur = a.read_volatile();
|
||||||
|
for _ in 0..500 { t = t * t % 10007; }
|
||||||
|
a.write_volatile(cur + 1);
|
||||||
|
mutex_unlock(0);
|
||||||
|
}
|
||||||
|
exit(t as i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn main() -> i32 {
|
||||||
|
let start = get_time();
|
||||||
|
assert_eq!(mutex_blocking_create(), 0);
|
||||||
|
let mut v = Vec::new();
|
||||||
|
for _ in 0..THREAD_COUNT {
|
||||||
|
v.push(thread_create(f as usize) as usize);
|
||||||
|
}
|
||||||
|
let mut time_cost = Vec::new();
|
||||||
|
for tid in v.iter() {
|
||||||
|
time_cost.push(waittid(*tid));
|
||||||
|
}
|
||||||
|
println!("time cost is {}ms", get_time() - start);
|
||||||
|
assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT);
|
||||||
|
0
|
||||||
|
}
|
@ -10,8 +10,8 @@ use user_lib::{mutex_create, mutex_lock, mutex_unlock};
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
const PER_THREAD: usize = 10000;
|
const PER_THREAD: usize = 1000;
|
||||||
const THREAD_COUNT: usize = 8;
|
const THREAD_COUNT: usize = 16;
|
||||||
|
|
||||||
unsafe fn f() -> ! {
|
unsafe fn f() -> ! {
|
||||||
let mut t = 2usize;
|
let mut t = 2usize;
|
||||||
|
@ -118,7 +118,8 @@ pub fn waittid(tid: usize) -> isize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutex_create() -> isize { sys_mutex_create() }
|
pub fn mutex_create() -> isize { sys_mutex_create(false) }
|
||||||
|
pub fn mutex_blocking_create() -> isize { sys_mutex_create(true) }
|
||||||
pub fn mutex_lock(mutex_id: usize) { sys_mutex_lock(mutex_id); }
|
pub fn mutex_lock(mutex_id: usize) { sys_mutex_lock(mutex_id); }
|
||||||
pub fn mutex_unlock(mutex_id: usize) { sys_mutex_unlock(mutex_id); }
|
pub fn mutex_unlock(mutex_id: usize) { sys_mutex_unlock(mutex_id); }
|
||||||
|
|
||||||
|
@ -97,8 +97,8 @@ pub fn sys_waittid(tid: usize) -> isize {
|
|||||||
syscall(SYSCALL_WAITTID, [tid, 0, 0])
|
syscall(SYSCALL_WAITTID, [tid, 0, 0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sys_mutex_create() -> isize {
|
pub fn sys_mutex_create(blocking: bool) -> isize {
|
||||||
syscall(SYSCALL_MUTEX_CREATE, [0, 0, 0])
|
syscall(SYSCALL_MUTEX_CREATE, [blocking as usize, 0, 0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sys_mutex_lock(id: usize) -> isize {
|
pub fn sys_mutex_lock(id: usize) -> isize {
|
||||||
|
Loading…
Reference in New Issue
Block a user