From 7225254d8a396a956a50bcf76d2589a807c4353b Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Thu, 7 Oct 2021 14:33:44 -0700 Subject: [PATCH] Add MutexBlocking. --- os/src/sync/mod.rs | 2 +- os/src/sync/mutex.rs | 49 ++++++++++++++++++++++- os/src/syscall/mod.rs | 2 +- os/src/syscall/sync.rs | 10 +++-- os/src/task/mod.rs | 9 +++++ os/src/task/task.rs | 1 + user/src/bin/race_adder.rs | 4 +- user/src/bin/race_adder_mutex_blocking.rs | 44 ++++++++++++++++++++ user/src/bin/race_adder_mutex_spin.rs | 4 +- user/src/lib.rs | 3 +- user/src/syscall.rs | 4 +- 11 files changed, 119 insertions(+), 13 deletions(-) create mode 100644 user/src/bin/race_adder_mutex_blocking.rs diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs index f2c92af1..605ce165 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -2,4 +2,4 @@ mod up; mod mutex; pub use up::UPSafeCell; -pub use mutex::{Mutex, MutexSpin}; +pub use mutex::{Mutex, MutexSpin, MutexBlocking}; diff --git a/os/src/sync/mutex.rs b/os/src/sync/mutex.rs index e486ad71..ef45bbf2 100644 --- a/os/src/sync/mutex.rs +++ b/os/src/sync/mutex.rs @@ -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, +} + +pub struct MutexBlockingInner { + locked: bool, + wait_queue: VecDeque>, +} + +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); + } + } +} diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index bf436399..e5054e19 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -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), diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index 770cd85f..1f080131 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -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()))); diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 75754012..c426d6f9 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -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(); diff --git a/os/src/task/task.rs b/os/src/task/task.rs index c5465066..b7e10797 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -74,4 +74,5 @@ impl TaskControlBlock { pub enum TaskStatus { Ready, Running, + Blocking, } diff --git a/user/src/bin/race_adder.rs b/user/src/bin/race_adder.rs index 68bee9f9..0392b346 100644 --- a/user/src/bin/race_adder.rs +++ b/user/src/bin/race_adder.rs @@ -9,8 +9,8 @@ use user_lib::{exit, thread_create, waittid, get_time}; use alloc::vec::Vec; static mut A: usize = 0; -const PER_THREAD: usize = 10000; -const THREAD_COUNT: usize = 8; +const PER_THREAD: usize = 1000; +const THREAD_COUNT: usize = 16; unsafe fn f() -> ! { let mut t = 2usize; diff --git a/user/src/bin/race_adder_mutex_blocking.rs b/user/src/bin/race_adder_mutex_blocking.rs new file mode 100644 index 00000000..3df340f7 --- /dev/null +++ b/user/src/bin/race_adder_mutex_blocking.rs @@ -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 +} diff --git a/user/src/bin/race_adder_mutex_spin.rs b/user/src/bin/race_adder_mutex_spin.rs index 1612a1bd..038e01aa 100644 --- a/user/src/bin/race_adder_mutex_spin.rs +++ b/user/src/bin/race_adder_mutex_spin.rs @@ -10,8 +10,8 @@ use user_lib::{mutex_create, mutex_lock, mutex_unlock}; use alloc::vec::Vec; static mut A: usize = 0; -const PER_THREAD: usize = 10000; -const THREAD_COUNT: usize = 8; +const PER_THREAD: usize = 1000; +const THREAD_COUNT: usize = 16; unsafe fn f() -> ! { let mut t = 2usize; diff --git a/user/src/lib.rs b/user/src/lib.rs index 7b23eb70..7d3dd70b 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -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_unlock(mutex_id: usize) { sys_mutex_unlock(mutex_id); } diff --git a/user/src/syscall.rs b/user/src/syscall.rs index f7c9c190..df6f4cb8 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -97,8 +97,8 @@ pub fn sys_waittid(tid: usize) -> isize { syscall(SYSCALL_WAITTID, [tid, 0, 0]) } -pub fn sys_mutex_create() -> isize { - syscall(SYSCALL_MUTEX_CREATE, [0, 0, 0]) +pub fn sys_mutex_create(blocking: bool) -> isize { + syscall(SYSCALL_MUTEX_CREATE, [blocking as usize, 0, 0]) } pub fn sys_mutex_lock(id: usize) -> isize {