add condvar in kernel and app

This commit is contained in:
Yu Chen 2021-12-13 15:30:27 +08:00
parent 1c0bbf4404
commit 713e78ea91
8 changed files with 243 additions and 34 deletions

39
os/src/sync/condvar.rs Normal file
View File

@ -0,0 +1,39 @@
use alloc::{sync::Arc, collections::VecDeque};
use crate::task::{add_task, TaskControlBlock, current_task, block_current_and_run_next};
use crate::sync::{Mutex, UPSafeCell};
pub struct Condvar {
pub inner: UPSafeCell<CondvarInner>,
}
pub struct CondvarInner {
pub wait_queue: VecDeque<Arc<TaskControlBlock>>,
}
impl Condvar {
pub fn new() -> Self {
Self {
inner: unsafe { UPSafeCell::new(
CondvarInner {
wait_queue: VecDeque::new(),
}
)},
}
}
pub fn signal(&self) {
let mut inner = self.inner.exclusive_access();
if let Some(task) = inner.wait_queue.pop_front() {
add_task(task);
}
}
pub fn wait(&self, mutex:Arc<dyn Mutex>) {
mutex.unlock();
let mut inner = self.inner.exclusive_access();
inner.wait_queue.push_back(current_task().unwrap());
drop(inner);
block_current_and_run_next();
mutex.lock();
}
}

View File

@ -1,7 +1,9 @@
mod up; mod up;
mod mutex; mod mutex;
mod semaphore; mod semaphore;
mod condvar;
pub use up::UPSafeCell; pub use up::UPSafeCell;
pub use mutex::{Mutex, MutexSpin, MutexBlocking}; pub use mutex::{Mutex, MutexSpin, MutexBlocking};
pub use semaphore::Semaphore; pub use semaphore::Semaphore;
pub use condvar::Condvar;

View File

@ -21,6 +21,9 @@ const SYSCALL_MUTEX_UNLOCK: usize = 1012;
const SYSCALL_SEMAPHORE_CREATE: usize = 1020; const SYSCALL_SEMAPHORE_CREATE: usize = 1020;
const SYSCALL_SEMAPHORE_UP: usize = 1021; const SYSCALL_SEMAPHORE_UP: usize = 1021;
const SYSCALL_SEMAPHORE_DOWN: usize = 1022; const SYSCALL_SEMAPHORE_DOWN: usize = 1022;
const SYSCALL_CONDVAR_CREATE: usize = 1030;
const SYSCALL_CONDVAR_SIGNAL: usize = 1031;
const SYSCALL_CONDVAR_WAIT: usize = 1032;
mod fs; mod fs;
mod process; mod process;
@ -57,6 +60,9 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]), SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]),
SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]), SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]),
SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]), SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]),
SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]),
SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]),
SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]),
_ => panic!("Unsupported syscall_id: {}", syscall_id), _ => panic!("Unsupported syscall_id: {}", syscall_id),
} }
} }

View File

@ -1,5 +1,5 @@
use crate::task::{current_task, current_process, block_current_and_run_next}; use crate::task::{current_task, current_process, block_current_and_run_next};
use crate::sync::{Mutex, MutexSpin, MutexBlocking, Semaphore}; use crate::sync::{Mutex, MutexSpin, MutexBlocking, Semaphore, Condvar};
use crate::timer::{get_time_ms, add_timer}; use crate::timer::{get_time_ms, add_timer};
use alloc::sync::Arc; use alloc::sync::Arc;
@ -88,3 +88,41 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize {
sem.down(); sem.down();
0 0
} }
pub fn sys_condvar_create(_arg: usize) -> isize {
let process = current_process();
let mut process_inner = process.inner_exclusive_access();
let id = if let Some(id) = process_inner
.condvar_list
.iter()
.enumerate()
.find(|(_, item)| item.is_none())
.map(|(id, _)| id) {
process_inner.condvar_list[id] = Some(Arc::new(Condvar::new()));
id
} else {
process_inner.condvar_list.push(Some(Arc::new(Condvar::new())));
process_inner.condvar_list.len() - 1
};
id as isize
}
pub fn sys_condvar_signal(condvar_id: usize) -> isize {
let process = current_process();
let process_inner = process.inner_exclusive_access();
let condvar = Arc::clone(process_inner.condvar_list[condvar_id].as_ref().unwrap());
drop(process_inner);
condvar.signal();
0
}
pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize {
let process = current_process();
let process_inner = process.inner_exclusive_access();
let condvar = Arc::clone(process_inner.condvar_list[condvar_id].as_ref().unwrap());
let mutex = Arc::clone(process_inner.mutex_list[mutex_id].as_ref().unwrap());
drop(process_inner);
condvar.wait(mutex);
0
}

View File

@ -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, Mutex, Semaphore}; use crate::sync::{UPSafeCell, Mutex, Semaphore, Condvar};
use core::cell::RefMut; use core::cell::RefMut;
use super::id::RecycleAllocator; use super::id::RecycleAllocator;
use super::TaskControlBlock; use super::TaskControlBlock;
@ -34,6 +34,7 @@ pub struct ProcessControlBlockInner {
pub task_res_allocator: RecycleAllocator, pub task_res_allocator: RecycleAllocator,
pub mutex_list: Vec<Option<Arc<dyn Mutex>>>, pub mutex_list: Vec<Option<Arc<dyn Mutex>>>,
pub semaphore_list: Vec<Option<Arc<Semaphore>>>, pub semaphore_list: Vec<Option<Arc<Semaphore>>>,
pub condvar_list: Vec<Option<Arc<Condvar>>>,
} }
impl ProcessControlBlockInner { impl ProcessControlBlockInner {
@ -99,6 +100,7 @@ impl ProcessControlBlock {
task_res_allocator: RecycleAllocator::new(), task_res_allocator: RecycleAllocator::new(),
mutex_list: Vec::new(), mutex_list: Vec::new(),
semaphore_list: Vec::new(), semaphore_list: Vec::new(),
condvar_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
@ -213,6 +215,7 @@ impl ProcessControlBlock {
task_res_allocator: RecycleAllocator::new(), task_res_allocator: RecycleAllocator::new(),
mutex_list: Vec::new(), mutex_list: Vec::new(),
semaphore_list: Vec::new(), semaphore_list: Vec::new(),
condvar_list: Vec::new(),
})} })}
}); });
// add child // add child

View File

@ -0,0 +1,56 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use user_lib::{condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock};
use user_lib::{thread_create, waittid, sleep};
use user_lib::exit;
use alloc::vec::Vec;
static mut A: usize = 0;
const CONDVAR_ID: usize = 0;
const MUTEX_ID: usize = 0;
unsafe fn first() -> ! {
sleep(10);
println!("First work, Change A --> 1 and wakeup Second");
mutex_lock(MUTEX_ID);
A=1;
condvar_signal(CONDVAR_ID);
mutex_unlock(MUTEX_ID);
exit(0)
}
unsafe fn second() -> ! {
println!("Second want to continue,but need to wait A=1");
mutex_lock(MUTEX_ID);
while A==0 {
println!("Second: A is {}", A);
condvar_wait(CONDVAR_ID, MUTEX_ID);
}
mutex_unlock(MUTEX_ID);
println!("A is {}, Second can work now", A);
exit(0)
}
#[no_mangle]
pub fn main() -> i32 {
// create condvar & mutex
assert_eq!(condvar_create() as usize, CONDVAR_ID);
assert_eq!(mutex_blocking_create() as usize, MUTEX_ID);
// create threads
let mut threads = Vec::new();
threads.push(thread_create(first as usize, 0));
threads.push(thread_create(second as usize, 0));
// wait for all threads to complete
for thread in threads.iter() {
waittid(*thread as usize);
}
println!("test_condvar passed!");
0
}

View File

@ -6,16 +6,16 @@
#[macro_use] #[macro_use]
pub mod console; pub mod console;
mod syscall;
mod lang_items; mod lang_items;
mod syscall;
extern crate alloc; extern crate alloc;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
use syscall::*;
use buddy_system_allocator::LockedHeap;
use alloc::vec::Vec; use alloc::vec::Vec;
use buddy_system_allocator::LockedHeap;
use syscall::*;
const USER_HEAP_SIZE: usize = 32768; const USER_HEAP_SIZE: usize = 32768;
@ -38,16 +38,16 @@ pub extern "C" fn _start(argc: usize, argv: usize) -> ! {
} }
let mut v: Vec<&'static str> = Vec::new(); let mut v: Vec<&'static str> = Vec::new();
for i in 0..argc { for i in 0..argc {
let str_start = unsafe { let str_start =
((argv + i * core::mem::size_of::<usize>()) as *const usize).read_volatile() unsafe { ((argv + i * core::mem::size_of::<usize>()) as *const usize).read_volatile() };
}; let len = (0usize..)
let len = (0usize..).find(|i| unsafe { .find(|i| unsafe { ((str_start + *i) as *const u8).read_volatile() == 0 })
((str_start + *i) as *const u8).read_volatile() == 0 .unwrap();
}).unwrap();
v.push( v.push(
core::str::from_utf8(unsafe { core::str::from_utf8(unsafe {
core::slice::from_raw_parts(str_start as *const u8, len) core::slice::from_raw_parts(str_start as *const u8, len)
}).unwrap() })
.unwrap(),
); );
} }
exit(main(argc, v.as_slice())); exit(main(argc, v.as_slice()));
@ -69,22 +69,48 @@ bitflags! {
} }
} }
pub fn dup(fd: usize) -> isize { sys_dup(fd) } pub fn dup(fd: usize) -> isize {
pub fn open(path: &str, flags: OpenFlags) -> isize { sys_open(path, flags.bits) } sys_dup(fd)
pub fn close(fd: usize) -> isize { sys_close(fd) } }
pub fn pipe(pipe_fd: &mut [usize]) -> isize { sys_pipe(pipe_fd) } pub fn open(path: &str, flags: OpenFlags) -> isize {
pub fn read(fd: usize, buf: &mut [u8]) -> isize { sys_read(fd, buf) } sys_open(path, flags.bits)
pub fn write(fd: usize, buf: &[u8]) -> isize { sys_write(fd, buf) } }
pub fn exit(exit_code: i32) -> ! { sys_exit(exit_code); } pub fn close(fd: usize) -> isize {
pub fn yield_() -> isize { sys_yield() } sys_close(fd)
pub fn get_time() -> isize { sys_get_time() } }
pub fn getpid() -> isize { sys_getpid() } pub fn pipe(pipe_fd: &mut [usize]) -> isize {
pub fn fork() -> isize { sys_fork() } sys_pipe(pipe_fd)
pub fn exec(path: &str, args: &[*const u8]) -> isize { sys_exec(path, args) } }
pub fn read(fd: usize, buf: &mut [u8]) -> isize {
sys_read(fd, buf)
}
pub fn write(fd: usize, buf: &[u8]) -> isize {
sys_write(fd, buf)
}
pub fn exit(exit_code: i32) -> ! {
sys_exit(exit_code);
}
pub fn yield_() -> isize {
sys_yield()
}
pub fn get_time() -> isize {
sys_get_time()
}
pub fn getpid() -> isize {
sys_getpid()
}
pub fn fork() -> isize {
sys_fork()
}
pub fn exec(path: &str, args: &[*const u8]) -> isize {
sys_exec(path, args)
}
pub fn wait(exit_code: &mut i32) -> isize { pub fn wait(exit_code: &mut i32) -> isize {
loop { loop {
match sys_waitpid(-1, exit_code as *mut _) { match sys_waitpid(-1, exit_code as *mut _) {
-2 => { yield_(); } -2 => {
yield_();
}
// -1 or a real pid // -1 or a real pid
exit_pid => return exit_pid, exit_pid => return exit_pid,
} }
@ -94,7 +120,9 @@ pub fn wait(exit_code: &mut i32) -> isize {
pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize {
loop { loop {
match sys_waitpid(pid as isize, exit_code as *mut _) { match sys_waitpid(pid as isize, exit_code as *mut _) {
-2 => { yield_(); } -2 => {
yield_();
}
// -1 or a real pid // -1 or a real pid
exit_pid => return exit_pid, exit_pid => return exit_pid,
} }
@ -104,21 +132,35 @@ pub fn sleep(sleep_ms: usize) {
sys_sleep(sleep_ms); sys_sleep(sleep_ms);
} }
pub fn thread_create(entry: usize, arg: usize) -> isize { sys_thread_create(entry, arg) } pub fn thread_create(entry: usize, arg: usize) -> isize {
pub fn gettid() -> isize { sys_gettid() } sys_thread_create(entry, arg)
}
pub fn gettid() -> isize {
sys_gettid()
}
pub fn waittid(tid: usize) -> isize { pub fn waittid(tid: usize) -> isize {
loop { loop {
match sys_waittid(tid) { match sys_waittid(tid) {
-2 => { yield_(); } -2 => {
yield_();
}
exit_code => return exit_code, exit_code => return exit_code,
} }
} }
} }
pub fn mutex_create() -> isize { sys_mutex_create(false) } pub fn mutex_create() -> isize {
pub fn mutex_blocking_create() -> isize { sys_mutex_create(true) } sys_mutex_create(false)
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_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);
}
pub fn semaphore_create(res_count: usize) -> isize { pub fn semaphore_create(res_count: usize) -> isize {
sys_semaphore_create(res_count) sys_semaphore_create(res_count)
} }
@ -128,4 +170,12 @@ pub fn semaphore_up(sem_id: usize) {
pub fn semaphore_down(sem_id: usize) { pub fn semaphore_down(sem_id: usize) {
sys_semaphore_down(sem_id); sys_semaphore_down(sem_id);
} }
pub fn condvar_create() -> isize {
sys_condvar_create(0)
}
pub fn condvar_signal(condvar_id: usize) {
sys_condvar_signal(condvar_id);
}
pub fn condvar_wait(condvar_id: usize, mutex_id: usize) {
sys_condvar_wait(condvar_id, mutex_id);
}

View File

@ -21,6 +21,9 @@ const SYSCALL_MUTEX_UNLOCK: usize = 1012;
const SYSCALL_SEMAPHORE_CREATE: usize = 1020; const SYSCALL_SEMAPHORE_CREATE: usize = 1020;
const SYSCALL_SEMAPHORE_UP: usize = 1021; const SYSCALL_SEMAPHORE_UP: usize = 1021;
const SYSCALL_SEMAPHORE_DOWN: usize = 1022; const SYSCALL_SEMAPHORE_DOWN: usize = 1022;
const SYSCALL_CONDVAR_CREATE: usize = 1030;
const SYSCALL_CONDVAR_SIGNAL: usize = 1031;
const SYSCALL_CONDVAR_WAIT: usize = 1032;
fn syscall(id: usize, args: [usize; 3]) -> isize { fn syscall(id: usize, args: [usize; 3]) -> isize {
let mut ret: isize; let mut ret: isize;
@ -128,3 +131,15 @@ pub fn sys_semaphore_up(sem_id: usize) -> isize {
pub fn sys_semaphore_down(sem_id: usize) -> isize { pub fn sys_semaphore_down(sem_id: usize) -> isize {
syscall(SYSCALL_SEMAPHORE_DOWN, [sem_id, 0, 0]) syscall(SYSCALL_SEMAPHORE_DOWN, [sem_id, 0, 0])
} }
pub fn sys_condvar_create(_arg: usize) -> isize {
syscall(SYSCALL_CONDVAR_CREATE, [_arg, 0, 0])
}
pub fn sys_condvar_signal(condvar_id: usize) -> isize {
syscall(SYSCALL_CONDVAR_SIGNAL, [condvar_id, 0, 0])
}
pub fn sys_condvar_wait(condvar_id: usize, mutex_id:usize) -> isize {
syscall(SYSCALL_CONDVAR_WAIT, [condvar_id, mutex_id, 0])
}