Add MutexSpin and several syscalls.
This commit is contained in:
parent
d1e55d85d8
commit
8974a29245
8 changed files with 159 additions and 2 deletions
|
@ -1,3 +1,5 @@
|
||||||
mod up;
|
mod up;
|
||||||
|
mod mutex;
|
||||||
|
|
||||||
pub use up::UPSafeCell;
|
pub use up::UPSafeCell;
|
||||||
|
pub use mutex::{Mutex, MutexSpin};
|
||||||
|
|
40
os/src/sync/mutex.rs
Normal file
40
os/src/sync/mutex.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
use super::UPSafeCell;
|
||||||
|
use crate::task::suspend_current_and_run_next;
|
||||||
|
|
||||||
|
pub trait Mutex: Sync + Send {
|
||||||
|
fn lock(&self);
|
||||||
|
fn unlock(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MutexSpin {
|
||||||
|
locked: UPSafeCell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MutexSpin {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
locked: unsafe { UPSafeCell::new(false) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mutex for MutexSpin {
|
||||||
|
fn lock(&self) {
|
||||||
|
loop {
|
||||||
|
let mut locked = self.locked.exclusive_access();
|
||||||
|
if *locked {
|
||||||
|
drop(locked);
|
||||||
|
suspend_current_and_run_next();
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
*locked = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unlock(&self) {
|
||||||
|
let mut locked = self.locked.exclusive_access();
|
||||||
|
*locked = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,14 +14,19 @@ const SYSCALL_WAITPID: usize = 260;
|
||||||
const SYSCALL_THREAD_CREATE: usize = 1000;
|
const SYSCALL_THREAD_CREATE: usize = 1000;
|
||||||
const SYSCALL_GETTID: usize = 1001;
|
const SYSCALL_GETTID: usize = 1001;
|
||||||
const SYSCALL_WAITTID: usize = 1002;
|
const SYSCALL_WAITTID: usize = 1002;
|
||||||
|
const SYSCALL_MUTEX_CREATE: usize = 1010;
|
||||||
|
const SYSCALL_MUTEX_LOCK: usize = 1011;
|
||||||
|
const SYSCALL_MUTEX_UNLOCK: usize = 1012;
|
||||||
|
|
||||||
mod fs;
|
mod fs;
|
||||||
mod process;
|
mod process;
|
||||||
mod thread;
|
mod thread;
|
||||||
|
mod sync;
|
||||||
|
|
||||||
use fs::*;
|
use fs::*;
|
||||||
use process::*;
|
use process::*;
|
||||||
use thread::*;
|
use thread::*;
|
||||||
|
use sync::*;
|
||||||
|
|
||||||
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
||||||
match syscall_id {
|
match syscall_id {
|
||||||
|
@ -41,6 +46,9 @@ 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_LOCK => sys_mutex_lock(args[0]),
|
||||||
|
SYSCALL_MUTEX_UNLOCK => sys_mutex_unlock(args[0]),
|
||||||
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
40
os/src/syscall/sync.rs
Normal file
40
os/src/syscall/sync.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
use crate::task::current_process;
|
||||||
|
use crate::sync::MutexSpin;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
pub fn sys_mutex_create() -> isize {
|
||||||
|
let process = current_process();
|
||||||
|
let mut process_inner = process.inner_exclusive_access();
|
||||||
|
if let Some(id) = process_inner
|
||||||
|
.mutex_list
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_, item)| item.is_none())
|
||||||
|
.map(|(id, _)| id) {
|
||||||
|
process_inner.mutex_list[id] = Some(Arc::new(MutexSpin::new()));
|
||||||
|
id as isize
|
||||||
|
} else {
|
||||||
|
process_inner.mutex_list.push(Some(Arc::new(MutexSpin::new())));
|
||||||
|
process_inner.mutex_list.len() as isize - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_mutex_lock(mutex_id: usize) -> isize {
|
||||||
|
let process = current_process();
|
||||||
|
let process_inner = process.inner_exclusive_access();
|
||||||
|
let mutex = Arc::clone(process_inner.mutex_list[mutex_id].as_ref().unwrap());
|
||||||
|
drop(process_inner);
|
||||||
|
drop(process);
|
||||||
|
mutex.lock();
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_mutex_unlock(mutex_id: usize) -> isize {
|
||||||
|
let process = current_process();
|
||||||
|
let process_inner = process.inner_exclusive_access();
|
||||||
|
let mutex = Arc::clone(process_inner.mutex_list[mutex_id].as_ref().unwrap());
|
||||||
|
drop(process_inner);
|
||||||
|
drop(process);
|
||||||
|
mutex.unlock();
|
||||||
|
0
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ use crate::mm::{
|
||||||
translated_refmut,
|
translated_refmut,
|
||||||
};
|
};
|
||||||
use crate::trap::{TrapContext, trap_handler};
|
use crate::trap::{TrapContext, trap_handler};
|
||||||
use crate::sync::UPSafeCell;
|
use crate::sync::{UPSafeCell, Mutex};
|
||||||
use core::cell::RefMut;
|
use core::cell::RefMut;
|
||||||
use super::id::RecycleAllocator;
|
use super::id::RecycleAllocator;
|
||||||
use super::TaskControlBlock;
|
use super::TaskControlBlock;
|
||||||
|
@ -32,6 +32,7 @@ pub struct ProcessControlBlockInner {
|
||||||
pub fd_table: Vec<Option<Arc<dyn File + Send + Sync>>>,
|
pub fd_table: Vec<Option<Arc<dyn File + Send + Sync>>>,
|
||||||
pub tasks: Vec<Option<Arc<TaskControlBlock>>>,
|
pub tasks: Vec<Option<Arc<TaskControlBlock>>>,
|
||||||
pub task_res_allocator: RecycleAllocator,
|
pub task_res_allocator: RecycleAllocator,
|
||||||
|
pub mutex_list: Vec<Option<Arc<dyn Mutex>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessControlBlockInner {
|
impl ProcessControlBlockInner {
|
||||||
|
@ -95,6 +96,7 @@ impl ProcessControlBlock {
|
||||||
],
|
],
|
||||||
tasks: Vec::new(),
|
tasks: Vec::new(),
|
||||||
task_res_allocator: RecycleAllocator::new(),
|
task_res_allocator: RecycleAllocator::new(),
|
||||||
|
mutex_list: Vec::new(),
|
||||||
})}
|
})}
|
||||||
});
|
});
|
||||||
// create a main thread, we should allocate ustack and trap_cx here
|
// create a main thread, we should allocate ustack and trap_cx here
|
||||||
|
@ -207,6 +209,7 @@ impl ProcessControlBlock {
|
||||||
fd_table: new_fd_table,
|
fd_table: new_fd_table,
|
||||||
tasks: Vec::new(),
|
tasks: Vec::new(),
|
||||||
task_res_allocator: RecycleAllocator::new(),
|
task_res_allocator: RecycleAllocator::new(),
|
||||||
|
mutex_list: Vec::new(),
|
||||||
})}
|
})}
|
||||||
});
|
});
|
||||||
// add child
|
// add child
|
||||||
|
|
44
user/src/bin/race_adder_mutex_spin.rs
Normal file
44
user/src/bin/race_adder_mutex_spin.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_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_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
|
||||||
|
}
|
|
@ -117,3 +117,8 @@ pub fn waittid(tid: usize) -> isize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mutex_create() -> isize { sys_mutex_create() }
|
||||||
|
pub fn mutex_lock(mutex_id: usize) { sys_mutex_lock(mutex_id); }
|
||||||
|
pub fn mutex_unlock(mutex_id: usize) { sys_mutex_unlock(mutex_id); }
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,9 @@ const SYSCALL_WAITPID: usize = 260;
|
||||||
const SYSCALL_THREAD_CREATE: usize = 1000;
|
const SYSCALL_THREAD_CREATE: usize = 1000;
|
||||||
const SYSCALL_GETTID: usize = 1001;
|
const SYSCALL_GETTID: usize = 1001;
|
||||||
const SYSCALL_WAITTID: usize = 1002;
|
const SYSCALL_WAITTID: usize = 1002;
|
||||||
|
const SYSCALL_MUTEX_CREATE: usize = 1010;
|
||||||
|
const SYSCALL_MUTEX_LOCK: usize = 1011;
|
||||||
|
const SYSCALL_MUTEX_UNLOCK: usize = 1012;
|
||||||
|
|
||||||
fn syscall(id: usize, args: [usize; 3]) -> isize {
|
fn syscall(id: usize, args: [usize; 3]) -> isize {
|
||||||
let mut ret: isize;
|
let mut ret: isize;
|
||||||
|
@ -93,3 +96,15 @@ pub fn sys_gettid() -> isize {
|
||||||
pub fn sys_waittid(tid: usize) -> isize {
|
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 {
|
||||||
|
syscall(SYSCALL_MUTEX_CREATE, [0, 0, 0])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_mutex_lock(id: usize) -> isize {
|
||||||
|
syscall(SYSCALL_MUTEX_LOCK, [id, 0, 0])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_mutex_unlock(id: usize) -> isize {
|
||||||
|
syscall(SYSCALL_MUTEX_UNLOCK, [id, 0, 0])
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue