From 713e78ea91ca666ffbe1a0b1a6a415d422673319 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Mon, 13 Dec 2021 15:30:27 +0800 Subject: [PATCH] add condvar in kernel and app --- os/src/sync/condvar.rs | 39 ++++++++++++ os/src/sync/mod.rs | 2 + os/src/syscall/mod.rs | 6 ++ os/src/syscall/sync.rs | 40 +++++++++++- os/src/task/process.rs | 5 +- user/src/bin/test_condvar.rs | 56 +++++++++++++++++ user/src/lib.rs | 114 +++++++++++++++++++++++++---------- user/src/syscall.rs | 15 +++++ 8 files changed, 243 insertions(+), 34 deletions(-) create mode 100644 os/src/sync/condvar.rs create mode 100644 user/src/bin/test_condvar.rs diff --git a/os/src/sync/condvar.rs b/os/src/sync/condvar.rs new file mode 100644 index 00000000..0b8f5670 --- /dev/null +++ b/os/src/sync/condvar.rs @@ -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, +} + +pub struct CondvarInner { + pub wait_queue: VecDeque>, +} + +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) { + 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(); + } +} diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs index ed39a630..8cf47c2a 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -1,7 +1,9 @@ mod up; mod mutex; mod semaphore; +mod condvar; pub use up::UPSafeCell; pub use mutex::{Mutex, MutexSpin, MutexBlocking}; pub use semaphore::Semaphore; +pub use condvar::Condvar; \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index c19c3fdf..5184abe0 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -21,6 +21,9 @@ const SYSCALL_MUTEX_UNLOCK: usize = 1012; const SYSCALL_SEMAPHORE_CREATE: usize = 1020; const SYSCALL_SEMAPHORE_UP: usize = 1021; 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 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_UP => sys_semaphore_up(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), } } diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index f49f1222..e92cf797 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -1,5 +1,5 @@ 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 alloc::sync::Arc; @@ -88,3 +88,41 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize { sem.down(); 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 +} \ No newline at end of file diff --git a/os/src/task/process.rs b/os/src/task/process.rs index af48f21a..43001b12 100644 --- a/os/src/task/process.rs +++ b/os/src/task/process.rs @@ -4,7 +4,7 @@ use crate::mm::{ translated_refmut, }; use crate::trap::{TrapContext, trap_handler}; -use crate::sync::{UPSafeCell, Mutex, Semaphore}; +use crate::sync::{UPSafeCell, Mutex, Semaphore, Condvar}; use core::cell::RefMut; use super::id::RecycleAllocator; use super::TaskControlBlock; @@ -34,6 +34,7 @@ pub struct ProcessControlBlockInner { pub task_res_allocator: RecycleAllocator, pub mutex_list: Vec>>, pub semaphore_list: Vec>>, + pub condvar_list: Vec>>, } impl ProcessControlBlockInner { @@ -99,6 +100,7 @@ impl ProcessControlBlock { task_res_allocator: RecycleAllocator::new(), mutex_list: Vec::new(), semaphore_list: Vec::new(), + condvar_list: Vec::new(), })} }); // create a main thread, we should allocate ustack and trap_cx here @@ -213,6 +215,7 @@ impl ProcessControlBlock { task_res_allocator: RecycleAllocator::new(), mutex_list: Vec::new(), semaphore_list: Vec::new(), + condvar_list: Vec::new(), })} }); // add child diff --git a/user/src/bin/test_condvar.rs b/user/src/bin/test_condvar.rs new file mode 100644 index 00000000..6aa49eff --- /dev/null +++ b/user/src/bin/test_condvar.rs @@ -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 +} diff --git a/user/src/lib.rs b/user/src/lib.rs index afde2ecc..4fe0e2a2 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -6,16 +6,16 @@ #[macro_use] pub mod console; -mod syscall; mod lang_items; +mod syscall; extern crate alloc; #[macro_use] extern crate bitflags; -use syscall::*; -use buddy_system_allocator::LockedHeap; use alloc::vec::Vec; +use buddy_system_allocator::LockedHeap; +use syscall::*; 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(); for i in 0..argc { - let str_start = unsafe { - ((argv + i * core::mem::size_of::()) as *const usize).read_volatile() - }; - let len = (0usize..).find(|i| unsafe { - ((str_start + *i) as *const u8).read_volatile() == 0 - }).unwrap(); + let str_start = + unsafe { ((argv + i * core::mem::size_of::()) as *const usize).read_volatile() }; + let len = (0usize..) + .find(|i| unsafe { ((str_start + *i) as *const u8).read_volatile() == 0 }) + .unwrap(); v.push( core::str::from_utf8(unsafe { core::slice::from_raw_parts(str_start as *const u8, len) - }).unwrap() + }) + .unwrap(), ); } exit(main(argc, v.as_slice())); @@ -69,22 +69,48 @@ bitflags! { } } -pub fn dup(fd: usize) -> isize { sys_dup(fd) } -pub fn open(path: &str, flags: OpenFlags) -> isize { sys_open(path, flags.bits) } -pub fn close(fd: usize) -> isize { sys_close(fd) } -pub fn pipe(pipe_fd: &mut [usize]) -> isize { sys_pipe(pipe_fd) } -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 dup(fd: usize) -> isize { + sys_dup(fd) +} +pub fn open(path: &str, flags: OpenFlags) -> isize { + sys_open(path, flags.bits) +} +pub fn close(fd: usize) -> isize { + sys_close(fd) +} +pub fn pipe(pipe_fd: &mut [usize]) -> isize { + sys_pipe(pipe_fd) +} +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 { loop { match sys_waitpid(-1, exit_code as *mut _) { - -2 => { yield_(); } + -2 => { + yield_(); + } // -1 or a real 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 { loop { match sys_waitpid(pid as isize, exit_code as *mut _) { - -2 => { yield_(); } + -2 => { + yield_(); + } // -1 or a real pid exit_pid => return exit_pid, } @@ -104,21 +132,35 @@ pub fn sleep(sleep_ms: usize) { sys_sleep(sleep_ms); } -pub fn thread_create(entry: usize, arg: usize) -> isize { sys_thread_create(entry, arg) } -pub fn gettid() -> isize { sys_gettid() } +pub fn thread_create(entry: usize, arg: usize) -> isize { + sys_thread_create(entry, arg) +} +pub fn gettid() -> isize { + sys_gettid() +} pub fn waittid(tid: usize) -> isize { loop { match sys_waittid(tid) { - -2 => { yield_(); } + -2 => { + yield_(); + } exit_code => return exit_code, } } } -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); } +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); +} pub fn semaphore_create(res_count: usize) -> isize { sys_semaphore_create(res_count) } @@ -128,4 +170,12 @@ pub fn semaphore_up(sem_id: usize) { pub fn semaphore_down(sem_id: usize) { 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); +} diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 64f738d2..8d5b6f5b 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -21,6 +21,9 @@ const SYSCALL_MUTEX_UNLOCK: usize = 1012; const SYSCALL_SEMAPHORE_CREATE: usize = 1020; const SYSCALL_SEMAPHORE_UP: usize = 1021; 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 { 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 { 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]) +}