From c2cda480899e7131a8b585968290354887863890 Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sat, 8 Mar 2025 13:35:07 +0800 Subject: [PATCH 01/14] Update Rust toolchain --- os/src/lang_items.rs | 4 ++-- os/src/main.rs | 1 - os/src/mm/heap_allocator.rs | 2 +- user/src/bin/condsync_condvar.rs | 4 ++-- user/src/bin/condsync_sem.rs | 4 ++-- user/src/bin/stackful_coroutine.rs | 5 ++--- user/src/lang_items.rs | 2 +- user/src/lib.rs | 3 +-- 8 files changed, 11 insertions(+), 14 deletions(-) diff --git a/os/src/lang_items.rs b/os/src/lang_items.rs index 021f16fa8..88fd6dc1d 100644 --- a/os/src/lang_items.rs +++ b/os/src/lang_items.rs @@ -11,10 +11,10 @@ fn panic(info: &PanicInfo) -> ! { "[kernel] Panicked at {}:{} {}", location.file(), location.line(), - info.message().unwrap() + info.message() ); } else { - error!("[kernel] Panicked: {}", info.message().unwrap()); + error!("[kernel] Panicked: {}", info.message()); } unsafe { backtrace(); diff --git a/os/src/main.rs b/os/src/main.rs index a5df470e6..35f00a45e 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -1,6 +1,5 @@ #![no_std] #![no_main] -#![feature(panic_info_message)] #![feature(alloc_error_handler)] extern crate alloc; diff --git a/os/src/mm/heap_allocator.rs b/os/src/mm/heap_allocator.rs index 42a6d7697..a7d7d56a9 100644 --- a/os/src/mm/heap_allocator.rs +++ b/os/src/mm/heap_allocator.rs @@ -15,7 +15,7 @@ pub fn init_heap() { unsafe { HEAP_ALLOCATOR .lock() - .init(HEAP_SPACE.as_ptr() as usize, KERNEL_HEAP_SIZE); + .init(&raw mut HEAP_SPACE as usize, KERNEL_HEAP_SIZE); } } diff --git a/user/src/bin/condsync_condvar.rs b/user/src/bin/condsync_condvar.rs index b83aeda21..51802c67e 100644 --- a/user/src/bin/condsync_condvar.rs +++ b/user/src/bin/condsync_condvar.rs @@ -32,10 +32,10 @@ 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); + println!("Second: A is {}", &raw mut A as usize); condvar_wait(CONDVAR_ID, MUTEX_ID); } - println!("A is {}, Second can work now", A); + println!("A is {}, Second can work now", &raw mut A as usize); mutex_unlock(MUTEX_ID); exit(0) } diff --git a/user/src/bin/condsync_sem.rs b/user/src/bin/condsync_sem.rs index ee08face4..bdea221a8 100644 --- a/user/src/bin/condsync_sem.rs +++ b/user/src/bin/condsync_sem.rs @@ -33,7 +33,7 @@ unsafe fn second() -> ! { loop { mutex_lock(MUTEX_ID); if A == 0 { - println!("Second: A is {}", A); + println!("Second: A is {}", &raw mut A as usize); mutex_unlock(MUTEX_ID); semaphore_down(SEM_ID); } else { @@ -41,7 +41,7 @@ unsafe fn second() -> ! { break; } } - println!("A is {}, Second can work now", A); + println!("A is {}, Second can work now", &raw mut A as usize); exit(0) } diff --git a/user/src/bin/stackful_coroutine.rs b/user/src/bin/stackful_coroutine.rs index 57ac03226..2bbafc38c 100644 --- a/user/src/bin/stackful_coroutine.rs +++ b/user/src/bin/stackful_coroutine.rs @@ -10,7 +10,7 @@ extern crate alloc; #[macro_use] extern crate user_lib; -use core::arch::asm; +use core::arch::naked_asm; //#[macro_use] use alloc::vec; @@ -262,7 +262,7 @@ pub fn yield_task() { #[no_mangle] unsafe extern "C" fn switch(old: *mut TaskContext, new: *const TaskContext) { // a0: _old, a1: _new - asm!( + naked_asm!( " sd x1, 0x00(a0) sd x2, 0x08(a0) @@ -298,7 +298,6 @@ unsafe extern "C" fn switch(old: *mut TaskContext, new: *const TaskContext) { jr t0 ", - options(noreturn) ); } diff --git a/user/src/lang_items.rs b/user/src/lang_items.rs index df0467c33..899e02911 100644 --- a/user/src/lang_items.rs +++ b/user/src/lang_items.rs @@ -2,7 +2,7 @@ use super::{getpid, kill, SignalFlags}; #[panic_handler] fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { - let err = panic_info.message().unwrap(); + let err = panic_info.message(); if let Some(location) = panic_info.location() { println!( "Panicked at {}:{}, {}", diff --git a/user/src/lib.rs b/user/src/lib.rs index bbaee3677..12d50dfdf 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -1,6 +1,5 @@ #![no_std] #![feature(linkage)] -#![feature(panic_info_message)] #![feature(alloc_error_handler)] #[macro_use] @@ -33,7 +32,7 @@ pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! { pub extern "C" fn _start(argc: usize, argv: usize) -> ! { unsafe { HEAP.lock() - .init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE); + .init(&raw mut HEAP_SPACE as usize, USER_HEAP_SIZE); } let mut v: Vec<&'static str> = Vec::new(); for i in 0..argc { From 6ab03c020869020069b46b78c0a88ab19e66ddf4 Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Wed, 9 Apr 2025 21:36:58 +0800 Subject: [PATCH 02/14] refactor(mutex): implement atomic-based MutexSpin and Futex - Refactor mutex module architecture - Add new MutexSpin and Futex implementations using atomic instructions - Introduce Futex support with following additions: * Atomic operations: increment/decrement/bit_test_set/add_and_compare * System Call: sys_futex * PCB member: futex_queues * MemorySet method: translation_va Todo: test the correctness of new Mutex --- .swp | Bin 0 -> 90112 bytes os/src/mm/memory_set.rs | 3 ++ os/src/sync/mod.rs | 68 +++++++++++++++++++++++- os/src/sync/mutex.rs | 113 +++++++++++++++++++++++++--------------- os/src/syscall/mod.rs | 72 +++++++++++++++---------- os/src/syscall/sync.rs | 43 +++++++++++++-- os/src/task/manager.rs | 6 +++ os/src/task/mod.rs | 1 + os/src/task/process.rs | 6 ++- os/src/trap/mod.rs | 4 +- 10 files changed, 238 insertions(+), 78 deletions(-) create mode 100644 .swp diff --git a/.swp b/.swp new file mode 100644 index 0000000000000000000000000000000000000000..d3b564b4a290627e72715694b40fa682bd750904 GIT binary patch literal 90112 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%0DkH)M-1{LL@2zpI^+{x(PdaP{iS#r00v z!WJt^XAAURJlSusa}&Uf~#D!So8TP*&fD3VoM$5QbxoE*0FFO1^EfWoss@?g=wgMAtjMAISd_5k z!0kK%3v**?5Dvt(*Rz#)${{P=?v8^jK5NB~TB=IAGi{dd*m-&wccVcMF{@OARvwJo zTP&@ixRsb%I(oo~XY!Id_Yv~=X8y~>qm%Tp@v};jEm$I@O-elsZHzsPMz=Onpd)XYeS;8r|fe(zE zDvzj1VXV}YEm@=H2ZziGXL9HKNP+32grNM-_0{QH`LMICou&DpU#?&*j_j|s3s}VV zSD8~)p(ac6rf=uUD3PPF%3pT9IUXBU7@W@6vk%N0J1BN)XAe@~d!m zJjkRlJ~L^AK(x$qRPhw-Lc8O6~N^6@n`ig1h&6k?KC3|v~3$P+nTwkAv z9uuk4WxHN?xy?CPVi$f=z?st=n9q^{CV(2H*#CcfXRsSb5rkpi2poBWIiT1g_DmeZ z!4?pL(Hcu(H?kKHk|na)RqPd;T`OY;5Cr8BxRbyIkhpUOiA%2V1c*Eb2fn|mx@R^H z76%R-Hc}_i&h$)mRdrAQ)zyC&D_WP$+id8123>Qj8eN1UR!6Ioe3gEqgI6}h%bG{O zPw>zn!UftgwB)g@EX+3aMYIN?7@mi`bRJ>1n!ZdaIS942b98iNgF==T52*Iu0OwT$|SLx9+<}F)5wJ_bJv|6dIJ|2vrfH_Btm50n=vUxM)ml$(@Glou#} zfbqYjd_%cFc?`z?it-ou{)nPI0e^z;f1&(L`H6Co@;&(eJ7Ijv^OXDG`!6V$DHY{w zu>EtCN67V%a)DwphJ1^E78+P+V4;D92L2lj6#t_?o!#!+0H6G!Bm$r>=&jSkHGSPI zEGo2TvnbnK$K-cb=#&k+Q9pqQM8T(35D)~r_1cxe{p_Z$Pu^r=QqJx+^w_+{7!7RU zU9VNLras-AdZz}TEc3PH`?0E*&rxrgdwL#m3)EJP4rqaxBX_jUGIEA9U02n6FdUSGfTyIrX z%_;8F>ENi0wpLWBtE;v=_j;Db;De=K)ZiQ8K$~MS&9o_^aFAjE*(4I`nMuV>N+SVi zK`G6Mm@g;TWV!AZ@G0}d2)axhTL=1#h!AfdPnFU99AWwD)-mt{NAttC)jl-a?G+zf+uOU=?Zdq&SC>UURXUxo*t1F6Ru(6N zh7N9fcKn&Ay8ZfNvA(%^8D`z}&7vcD_Cp?EIRMC%x?1c`hgjk|TM;o{v2)}4y^Tv- zmKMwZ6RmQwp_Cpw{j_*3xoz@RXuVXot`3hU<pL(QwfJ84?{)E&#*k&>sW)_EE?*_#&xk8sX;P-A zVtODh173QSvLw;A5S*oMwi%IPZ>AX| z;xDpL%Pi4XQ~UU4pq2vuIOk;`eGk-B52yMrT{rZcZsl)0)bn=5gQN6| zECd>f_2wkZDY>e2v;-na;8kyJMKS2P?U1$9u|-siD2IqGPp9S)s^OX)K)+~weqo85 zW}4-zZFN$gm(ihVn|hYEs% zl-C9td*amcJm|V31)Ja?dM>CIAKByl(K|%5P&Zy`{_LVho{>K=2o1SM=Hf Option { self.page_table.translate(vpn) } + pub fn translate_va(&self, va: VirtAddr) -> Option { + self.page_table.translate_va(va) + } pub fn recycle_data_pages(&mut self) { //*self = Self::new_bare(); self.areas.clear(); diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs index 7e948aa6c..814be77e5 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -4,6 +4,72 @@ mod semaphore; mod up; pub use condvar::Condvar; -pub use mutex::{Mutex, MutexBlocking, MutexSpin}; +pub use mutex::{FUTEX_WAIT, FUTEX_WAKE}; +pub use mutex::{Mutex, Futex, MutexSpin, FutexQ}; pub use semaphore::Semaphore; pub use up::UPSafeCell; + +#[inline(always)] +pub fn load_reserved(addr: *const u32) -> u32 { + let val; + unsafe { + core::arch::asm!( + "lr.w {}, ({})", + out(reg) val, + in(reg) addr + ); + } + val +} + +/// return true if successfully modify `addr` in memory +#[inline(always)] +pub fn store_conditional(addr: *const u32, val: u32) -> bool { + let res: u32; + unsafe { + core::arch::asm!( + "sc.w {}, {}, ({})", + out(reg) res, + in(reg) val, + in(reg) addr + ); + } + res == 0 +} + +#[inline(always)] +pub fn atomic_increment(addr: *mut u32) { + loop { + let val = load_reserved(addr); + if store_conditional(addr, val + 1) { break; } + } +} + +#[inline(always)] +pub fn atomic_decrement(addr: *mut u32) { + loop { + let val = load_reserved(addr); + if store_conditional(addr, val - 1) { break; } + } +} + +#[inline(always)] +pub fn atomic_test_and_set(addr: *mut u32, bit: u32) -> u32 { + loop { + let val = load_reserved(addr); + if store_conditional(addr, val | (1 << bit)) { return val; } + } +} + +/// 原子地使 `(addr)` 自加 `addend`,并比较结果与 `expected` 是否相等。 +/// 相等则返回 `true` +#[inline(always)] +pub fn atomic_add_and_compare(addr: *mut u32, addend: u32, expected: u32) -> bool { + loop { + let val = load_reserved(addr); + let res = val + addend; + if store_conditional(addr, res) { + return res == expected + } + } +} \ No newline at end of file diff --git a/os/src/sync/mutex.rs b/os/src/sync/mutex.rs index 5afcba041..e68b2d847 100644 --- a/os/src/sync/mutex.rs +++ b/os/src/sync/mutex.rs @@ -1,88 +1,115 @@ -use super::UPSafeCell; +use super::{atomic_add_and_compare, atomic_decrement, atomic_increment, atomic_test_and_set, load_reserved, store_conditional}; +use core::cell::UnsafeCell; use crate::task::TaskControlBlock; -use crate::task::{block_current_and_run_next, suspend_current_and_run_next}; -use crate::task::{current_task, wakeup_task}; +use crate::syscall::syscall; +use crate::syscall::SYSCALL_FUTEX; use alloc::{collections::VecDeque, sync::Arc}; +pub const FUTEX_WAIT: usize = 0; +pub const FUTEX_WAKE: usize = 1; pub trait Mutex: Sync + Send { fn lock(&self); fn unlock(&self); } pub struct MutexSpin { - locked: UPSafeCell, + locked: UnsafeCell, } +unsafe impl Send for MutexSpin {} +unsafe impl Sync for MutexSpin {} + impl MutexSpin { pub fn new() -> Self { Self { - locked: unsafe { UPSafeCell::new(false) }, + locked: UnsafeCell::new(0), } } } impl Mutex for MutexSpin { fn lock(&self) { + let addr = self.locked.get() as *const u32; loop { - let mut locked = self.locked.exclusive_access(); - if *locked { - drop(locked); - suspend_current_and_run_next(); - continue; - } else { - *locked = true; - return; - } + while load_reserved(addr) == 1 {} + if store_conditional(addr, 0) { break; } } } fn unlock(&self) { - let mut locked = self.locked.exclusive_access(); - *locked = false; + let addr = self.locked.get(); + unsafe { *addr = 0; } } } -pub struct MutexBlocking { - inner: UPSafeCell, +/// 只允许在用户态使用 Futex +pub struct Futex { + flag: UnsafeCell, } -pub struct MutexBlockingInner { - locked: bool, - wait_queue: VecDeque>, +unsafe impl Send for Futex {} +unsafe impl Sync for Futex {} + +// Futex的等待队列,由位于内核的进程控制块维护 +pub struct FutexQ { + pub guard: MutexSpin, + queue: UnsafeCell>>, } -impl MutexBlocking { +impl Futex { pub fn new() -> Self { Self { - inner: unsafe { - UPSafeCell::new(MutexBlockingInner { - locked: false, - wait_queue: VecDeque::new(), - }) - }, + flag: UnsafeCell::new(0), } } } -impl Mutex for MutexBlocking { +impl Mutex for Futex { 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; + let addr = self.flag.get(); + if atomic_test_and_set(addr as *mut u32, 31) == 0 { + // fastpath + return; + } + // one more waiter + atomic_increment(addr as *mut u32); + loop { + if atomic_test_and_set(addr as *mut u32, 31) == 0 { + atomic_decrement(addr as *mut u32); + return; + } + let flag = unsafe { *addr }; + if flag >= 0 { continue; } + // we have to wait now + syscall(SYSCALL_FUTEX, [addr as usize, FUTEX_WAIT, flag as usize]); } } fn unlock(&self) { - let mut mutex_inner = self.inner.exclusive_access(); - assert!(mutex_inner.locked); - if let Some(waking_task) = mutex_inner.wait_queue.pop_front() { - wakeup_task(waking_task); - } else { - mutex_inner.locked = false; - } + let addr = self.flag.get(); + if atomic_add_and_compare(addr as *mut u32, 0x80000000, 0) { + // no threads are waiting + return; + } + syscall(SYSCALL_FUTEX, [addr as usize, FUTEX_WAKE, 0]); } } + +impl FutexQ { + pub fn new() -> Self { + Self { + guard: MutexSpin::new(), + queue: UnsafeCell::new(VecDeque::new()), + } + } + + /// 外部调用必须确保已拿到 FutexQ 的自旋锁 + pub fn push_back(&self, task: Arc) { + unsafe { &mut *self.queue.get() }.push_back(task); + } + + /// 外部调用必须确保已拿到 FutexQ 的自旋锁 + pub fn pop_front(&self) -> Arc { + unsafe { &mut *self.queue.get() }.pop_front().unwrap() + } +} \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index ca3fc526c..4101bc737 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,30 +1,31 @@ -const SYSCALL_DUP: usize = 24; -const SYSCALL_OPEN: usize = 56; -const SYSCALL_CLOSE: usize = 57; -const SYSCALL_PIPE: usize = 59; -const SYSCALL_READ: usize = 63; -const SYSCALL_WRITE: usize = 64; -const SYSCALL_EXIT: usize = 93; -const SYSCALL_SLEEP: usize = 101; -const SYSCALL_YIELD: usize = 124; -const SYSCALL_KILL: usize = 129; -const SYSCALL_GET_TIME: usize = 169; -const SYSCALL_GETPID: usize = 172; -const SYSCALL_FORK: usize = 220; -const SYSCALL_EXEC: usize = 221; -const SYSCALL_WAITPID: usize = 260; -const SYSCALL_THREAD_CREATE: usize = 1000; -const SYSCALL_GETTID: usize = 1001; -const SYSCALL_WAITTID: usize = 1002; -const SYSCALL_MUTEX_CREATE: usize = 1010; -const SYSCALL_MUTEX_LOCK: usize = 1011; -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; +pub const SYSCALL_DUP: usize = 24; +pub const SYSCALL_OPEN: usize = 56; +pub const SYSCALL_CLOSE: usize = 57; +pub const SYSCALL_PIPE: usize = 59; +pub const SYSCALL_READ: usize = 63; +pub const SYSCALL_WRITE: usize = 64; +pub const SYSCALL_EXIT: usize = 93; +pub const SYSCALL_SLEEP: usize = 101; +pub const SYSCALL_YIELD: usize = 124; +pub const SYSCALL_KILL: usize = 129; +pub const SYSCALL_GET_TIME: usize = 169; +pub const SYSCALL_GETPID: usize = 172; +pub const SYSCALL_FORK: usize = 220; +pub const SYSCALL_EXEC: usize = 221; +pub const SYSCALL_FUTEX: usize = 240; +pub const SYSCALL_WAITPID: usize = 260; +pub const SYSCALL_THREAD_CREATE: usize = 1000; +pub const SYSCALL_GETTID: usize = 1001; +pub const SYSCALL_WAITTID: usize = 1002; +pub const SYSCALL_MUTEX_CREATE: usize = 1010; +pub const SYSCALL_MUTEX_LOCK: usize = 1011; +pub const SYSCALL_MUTEX_UNLOCK: usize = 1012; +pub const SYSCALL_SEMAPHORE_CREATE: usize = 1020; +pub const SYSCALL_SEMAPHORE_UP: usize = 1021; +pub const SYSCALL_SEMAPHORE_DOWN: usize = 1022; +pub const SYSCALL_CONDVAR_CREATE: usize = 1030; +pub const SYSCALL_CONDVAR_SIGNAL: usize = 1031; +pub const SYSCALL_CONDVAR_WAIT: usize = 1032; mod fs; mod process; @@ -36,7 +37,21 @@ use process::*; use sync::*; use thread::*; -pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { +pub fn syscall(id: usize, args: [usize; 3]) -> isize { + let mut ret: isize; + unsafe { + core::arch::asm!( + "ecall", + inlateout("x10") args[0] => ret, + in("x11") args[1], + in("x12") args[2], + in("x17") id + ); + } + ret +} + +pub fn syscall_handler(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { SYSCALL_DUP => sys_dup(args[0]), SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32), @@ -52,6 +67,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_GETPID => sys_getpid(), SYSCALL_FORK => sys_fork(), SYSCALL_EXEC => sys_exec(args[0] as *const u8, args[1] as *const usize), + SYSCALL_FUTEX => sys_futex(args[0] as *const i32, args[1], args[2]), SYSCALL_WAITPID => sys_waitpid(args[0] as isize, args[1] as *mut i32), SYSCALL_THREAD_CREATE => sys_thread_create(args[0], args[1]), SYSCALL_GETTID => sys_gettid(), diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index eb67583ad..b3d630aaa 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -1,6 +1,7 @@ -use crate::sync::{Condvar, Mutex, MutexBlocking, MutexSpin, Semaphore}; -use crate::task::{block_current_and_run_next, current_process, current_task}; +use crate::sync::{Condvar, Mutex, Futex, MutexSpin, Semaphore}; +use crate::task::{block_current_and_run_next, current_process, current_task, wakeup_task, block_task, take_current_task}; use crate::timer::{add_timer, get_time_ms}; +use crate::sync::{FUTEX_WAIT, FUTEX_WAKE}; use alloc::sync::Arc; pub fn sys_sleep(ms: usize) -> isize { @@ -16,7 +17,7 @@ pub fn sys_mutex_create(blocking: bool) -> isize { let mutex: Option> = if !blocking { Some(Arc::new(MutexSpin::new())) } else { - Some(Arc::new(MutexBlocking::new())) + Some(Arc::new(Futex::new())) }; let mut process_inner = process.inner_exclusive_access(); if let Some(id) = process_inner @@ -132,3 +133,39 @@ pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize { condvar.wait(mutex); 0 } + +/// 封装在 Futex 方法中,不应直接调用 +pub fn sys_futex(uaddr: *const i32, futex_op: usize, val: usize) -> isize{ + let process = current_process(); + let process_inner = process.inner_exclusive_access(); + let futex_q = process_inner.futex_queues.get(&(uaddr as usize)).unwrap(); + let phys_addr = process_inner + .memory_set + .translate_va((uaddr as usize).into()) + .unwrap() + .0 as *const i32; + match futex_op { + FUTEX_WAIT => { + futex_q.guard.lock(); + if unsafe { *phys_addr == (val as i32)} { + // *addr等于预期值,标记 task 为阻塞,加入 futex 等待队列 + let task = take_current_task().unwrap(); + block_task(task.clone()); + futex_q.push_back(task); + futex_q.guard.unlock(); + + } else { + futex_q.guard.unlock(); + return 0; + } + }, + FUTEX_WAKE => { + futex_q.guard.lock(); + let task = futex_q.pop_front(); + wakeup_task(task); + futex_q.guard.unlock(); + }, + _ => panic!("Unsupported futex_op: {}", futex_op) + }; + 0 +} \ No newline at end of file diff --git a/os/src/task/manager.rs b/os/src/task/manager.rs index 21d35ee4f..cfe73499f 100644 --- a/os/src/task/manager.rs +++ b/os/src/task/manager.rs @@ -44,6 +44,12 @@ pub fn add_task(task: Arc) { TASK_MANAGER.exclusive_access().add(task); } +pub fn block_task(task: Arc) { + let mut task_inner = task.inner_exclusive_access(); + task_inner.task_status = TaskStatus::Blocked; + drop(task_inner); +} + pub fn wakeup_task(task: Arc) { let mut task_inner = task.inner_exclusive_access(); task_inner.task_status = TaskStatus::Ready; diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index d96deb666..c71406e61 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -27,6 +27,7 @@ pub use processor::{ }; pub use signal::SignalFlags; pub use task::{TaskControlBlock, TaskStatus}; +pub use manager::block_task; pub fn suspend_current_and_run_next() { // There must be an application running. diff --git a/os/src/task/process.rs b/os/src/task/process.rs index ffff14fe7..d6b4e54d4 100644 --- a/os/src/task/process.rs +++ b/os/src/task/process.rs @@ -5,12 +5,13 @@ use super::{add_task, SignalFlags}; use super::{pid_alloc, PidHandle}; use crate::fs::{File, Stdin, Stdout}; use crate::mm::{translated_refmut, MemorySet, KERNEL_SPACE}; -use crate::sync::{Condvar, Mutex, Semaphore, UPSafeCell}; +use crate::sync::{Condvar, Mutex, Semaphore, UPSafeCell, FutexQ}; use crate::trap::{trap_handler, TrapContext}; use alloc::string::String; use alloc::sync::{Arc, Weak}; use alloc::vec; use alloc::vec::Vec; +use alloc::collections::btree_map::BTreeMap; use core::cell::RefMut; pub struct ProcessControlBlock { @@ -31,6 +32,7 @@ pub struct ProcessControlBlockInner { pub tasks: Vec>>, pub task_res_allocator: RecycleAllocator, pub mutex_list: Vec>>, + pub futex_queues: BTreeMap, pub semaphore_list: Vec>>, pub condvar_list: Vec>>, } @@ -98,6 +100,7 @@ impl ProcessControlBlock { tasks: Vec::new(), task_res_allocator: RecycleAllocator::new(), mutex_list: Vec::new(), + futex_queues: BTreeMap::new(), semaphore_list: Vec::new(), condvar_list: Vec::new(), }) @@ -217,6 +220,7 @@ impl ProcessControlBlock { tasks: Vec::new(), task_res_allocator: RecycleAllocator::new(), mutex_list: Vec::new(), + futex_queues: BTreeMap::new(), semaphore_list: Vec::new(), condvar_list: Vec::new(), }) diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 6397811ae..c0bcd4455 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -1,7 +1,7 @@ mod context; use crate::config::TRAMPOLINE; -use crate::syscall::syscall; +use crate::syscall::syscall_handler; use crate::task::{ check_signals_of_current, current_add_signal, current_trap_cx, current_trap_cx_user_va, current_user_token, exit_current_and_run_next, suspend_current_and_run_next, SignalFlags, @@ -49,7 +49,7 @@ pub fn trap_handler() -> ! { let mut cx = current_trap_cx(); cx.sepc += 4; // get system call return value - let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]); + let result = syscall_handler(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]); // cx is changed during sys_exec, so we have to call it again cx = current_trap_cx(); cx.x[10] = result as usize; From bba9a42eb9015278794dcab076bd467cf5057cdb Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sat, 12 Apr 2025 14:31:46 +0800 Subject: [PATCH 03/14] refactor(mutex): adjust structure of mutex mod - Copy MutexSpin to user lib - Cut Futex from os/sync/mutex.rs to user lib - delete some mutex syscalls Todo: test the correctness of new Mutex Todo: reconstruct Condvar --- os/src/lib.rs | 24 ++++++++++++++ os/src/sync/mod.rs | 2 +- os/src/sync/mutex.rs | 51 +--------------------------- os/src/syscall/mod.rs | 20 ----------- os/src/syscall/sync.rs | 45 +------------------------ os/src/task/process.rs | 3 -- user/src/lib.rs | 17 ++++------ user/src/sync/mod.rs | 68 ++++++++++++++++++++++++++++++++++++++ user/src/sync/mutex.rs | 75 ++++++++++++++++++++++++++++++++++++++++++ user/src/syscall.rs | 20 +++++------ 10 files changed, 186 insertions(+), 139 deletions(-) create mode 100644 os/src/lib.rs create mode 100644 user/src/sync/mod.rs create mode 100644 user/src/sync/mutex.rs diff --git a/os/src/lib.rs b/os/src/lib.rs new file mode 100644 index 000000000..13de31993 --- /dev/null +++ b/os/src/lib.rs @@ -0,0 +1,24 @@ +#![no_std] +#![feature(alloc_error_handler)] + +extern crate alloc; + +#[macro_use] +extern crate bitflags; + +#[path = "boards/qemu.rs"] +mod board; + +#[macro_use] +pub mod console; +pub mod config; +pub mod drivers; +pub mod fs; +pub mod lang_items; +pub mod mm; +pub mod sbi; +pub mod sync; +pub mod syscall; +pub mod task; +pub mod timer; +pub mod trap; \ No newline at end of file diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs index 814be77e5..ed5d59c49 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -5,7 +5,7 @@ mod up; pub use condvar::Condvar; pub use mutex::{FUTEX_WAIT, FUTEX_WAKE}; -pub use mutex::{Mutex, Futex, MutexSpin, FutexQ}; +pub use mutex::{Mutex, MutexSpin, FutexQ}; pub use semaphore::Semaphore; pub use up::UPSafeCell; diff --git a/os/src/sync/mutex.rs b/os/src/sync/mutex.rs index e68b2d847..dd237c26e 100644 --- a/os/src/sync/mutex.rs +++ b/os/src/sync/mutex.rs @@ -1,8 +1,6 @@ -use super::{atomic_add_and_compare, atomic_decrement, atomic_increment, atomic_test_and_set, load_reserved, store_conditional}; +use super::{load_reserved, store_conditional}; use core::cell::UnsafeCell; use crate::task::TaskControlBlock; -use crate::syscall::syscall; -use crate::syscall::SYSCALL_FUTEX; use alloc::{collections::VecDeque, sync::Arc}; pub const FUTEX_WAIT: usize = 0; @@ -42,59 +40,12 @@ impl Mutex for MutexSpin { } } -/// 只允许在用户态使用 Futex -pub struct Futex { - flag: UnsafeCell, -} - -unsafe impl Send for Futex {} -unsafe impl Sync for Futex {} - // Futex的等待队列,由位于内核的进程控制块维护 pub struct FutexQ { pub guard: MutexSpin, queue: UnsafeCell>>, } -impl Futex { - pub fn new() -> Self { - Self { - flag: UnsafeCell::new(0), - } - } -} - -impl Mutex for Futex { - fn lock(&self) { - let addr = self.flag.get(); - if atomic_test_and_set(addr as *mut u32, 31) == 0 { - // fastpath - return; - } - // one more waiter - atomic_increment(addr as *mut u32); - loop { - if atomic_test_and_set(addr as *mut u32, 31) == 0 { - atomic_decrement(addr as *mut u32); - return; - } - let flag = unsafe { *addr }; - if flag >= 0 { continue; } - // we have to wait now - syscall(SYSCALL_FUTEX, [addr as usize, FUTEX_WAIT, flag as usize]); - } - } - - fn unlock(&self) { - let addr = self.flag.get(); - if atomic_add_and_compare(addr as *mut u32, 0x80000000, 0) { - // no threads are waiting - return; - } - syscall(SYSCALL_FUTEX, [addr as usize, FUTEX_WAKE, 0]); - } -} - impl FutexQ { pub fn new() -> Self { Self { diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 4101bc737..a7e4c57a1 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -17,9 +17,6 @@ pub const SYSCALL_WAITPID: usize = 260; pub const SYSCALL_THREAD_CREATE: usize = 1000; pub const SYSCALL_GETTID: usize = 1001; pub const SYSCALL_WAITTID: usize = 1002; -pub const SYSCALL_MUTEX_CREATE: usize = 1010; -pub const SYSCALL_MUTEX_LOCK: usize = 1011; -pub const SYSCALL_MUTEX_UNLOCK: usize = 1012; pub const SYSCALL_SEMAPHORE_CREATE: usize = 1020; pub const SYSCALL_SEMAPHORE_UP: usize = 1021; pub const SYSCALL_SEMAPHORE_DOWN: usize = 1022; @@ -37,20 +34,6 @@ use process::*; use sync::*; use thread::*; -pub fn syscall(id: usize, args: [usize; 3]) -> isize { - let mut ret: isize; - unsafe { - core::arch::asm!( - "ecall", - inlateout("x10") args[0] => ret, - in("x11") args[1], - in("x12") args[2], - in("x17") id - ); - } - ret -} - pub fn syscall_handler(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { SYSCALL_DUP => sys_dup(args[0]), @@ -72,9 +55,6 @@ pub fn syscall_handler(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_THREAD_CREATE => sys_thread_create(args[0], args[1]), SYSCALL_GETTID => sys_gettid(), SYSCALL_WAITTID => sys_waittid(args[0]) as isize, - 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]), SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]), SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]), SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]), diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index b3d630aaa..56e256c3f 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -1,4 +1,4 @@ -use crate::sync::{Condvar, Mutex, Futex, MutexSpin, Semaphore}; +use crate::sync::{Condvar, Mutex, Semaphore}; use crate::task::{block_current_and_run_next, current_process, current_task, wakeup_task, block_task, take_current_task}; use crate::timer::{add_timer, get_time_ms}; use crate::sync::{FUTEX_WAIT, FUTEX_WAKE}; @@ -12,49 +12,6 @@ pub fn sys_sleep(ms: usize) -> isize { 0 } -pub fn sys_mutex_create(blocking: bool) -> isize { - let process = current_process(); - let mutex: Option> = if !blocking { - Some(Arc::new(MutexSpin::new())) - } else { - Some(Arc::new(Futex::new())) - }; - 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] = mutex; - id as isize - } else { - process_inner.mutex_list.push(mutex); - 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 -} - pub fn sys_semaphore_create(res_count: usize) -> isize { let process = current_process(); let mut process_inner = process.inner_exclusive_access(); diff --git a/os/src/task/process.rs b/os/src/task/process.rs index d6b4e54d4..a7d713a8f 100644 --- a/os/src/task/process.rs +++ b/os/src/task/process.rs @@ -31,7 +31,6 @@ pub struct ProcessControlBlockInner { pub signals: SignalFlags, pub tasks: Vec>>, pub task_res_allocator: RecycleAllocator, - pub mutex_list: Vec>>, pub futex_queues: BTreeMap, pub semaphore_list: Vec>>, pub condvar_list: Vec>>, @@ -99,7 +98,6 @@ impl ProcessControlBlock { signals: SignalFlags::empty(), tasks: Vec::new(), task_res_allocator: RecycleAllocator::new(), - mutex_list: Vec::new(), futex_queues: BTreeMap::new(), semaphore_list: Vec::new(), condvar_list: Vec::new(), @@ -219,7 +217,6 @@ impl ProcessControlBlock { signals: SignalFlags::empty(), tasks: Vec::new(), task_res_allocator: RecycleAllocator::new(), - mutex_list: Vec::new(), futex_queues: BTreeMap::new(), semaphore_list: Vec::new(), condvar_list: Vec::new(), diff --git a/user/src/lib.rs b/user/src/lib.rs index 12d50dfdf..5e93c35f5 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -6,6 +6,7 @@ pub mod console; mod lang_items; mod syscall; +mod sync; extern crate alloc; #[macro_use] @@ -166,18 +167,14 @@ pub fn waittid(tid: usize) -> isize { } } -pub fn mutex_create() -> isize { - sys_mutex_create(false) +pub fn futex_wait(flag_addr: *mut i32, expect: i32) -> isize { + sys_futex_wait(flag_addr, expect) } -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 futex_wake(flag_addr: *mut i32) -> isize { + sys_futex_wake(flag_addr) } + pub fn semaphore_create(res_count: usize) -> isize { sys_semaphore_create(res_count) } diff --git a/user/src/sync/mod.rs b/user/src/sync/mod.rs new file mode 100644 index 000000000..514a18fc3 --- /dev/null +++ b/user/src/sync/mod.rs @@ -0,0 +1,68 @@ +mod mutex; + +pub use mutex::*; + +#[inline(always)] +pub fn load_reserved(addr: *const u32) -> u32 { + let val; + unsafe { + core::arch::asm!( + "lr.w {}, ({})", + out(reg) val, + in(reg) addr + ); + } + val +} + +/// return true if successfully modify `addr` in memory +#[inline(always)] +pub fn store_conditional(addr: *const u32, val: u32) -> bool { + let res: u32; + unsafe { + core::arch::asm!( + "sc.w {}, {}, ({})", + out(reg) res, + in(reg) val, + in(reg) addr + ); + } + res == 0 +} + +#[inline(always)] +pub fn atomic_increment(addr: *mut u32) { + loop { + let val = load_reserved(addr); + if store_conditional(addr, val + 1) { break; } + } +} + +#[inline(always)] +pub fn atomic_decrement(addr: *mut u32) { + loop { + let val = load_reserved(addr); + if store_conditional(addr, val - 1) { break; } + } +} + +#[inline(always)] +pub fn atomic_test_and_set(addr: *mut u32, bit: u32) -> u32 { + loop { + let val = load_reserved(addr); + if store_conditional(addr, val | (1 << bit)) { return val; } + } +} + +/// 原子地使 `(addr)` 自加 `addend`,并比较结果与 `expected` 是否相等。 +/// 相等则返回 `true` +#[inline(always)] +pub fn atomic_add_and_compare(addr: *mut u32, addend: u32, expected: u32) -> bool { + loop { + let val = load_reserved(addr); + let res = val + addend; + if store_conditional(addr, res) { + return res == expected + } + } +} \ No newline at end of file diff --git a/user/src/sync/mutex.rs b/user/src/sync/mutex.rs new file mode 100644 index 000000000..33863e3e4 --- /dev/null +++ b/user/src/sync/mutex.rs @@ -0,0 +1,75 @@ +use super::*; +use core::cell::UnsafeCell; +use crate::syscall::{self, sys_futex_wait, sys_futex_wake}; + +pub struct MutexSpin { + locked: UnsafeCell, +} + +unsafe impl Send for MutexSpin {} +unsafe impl Sync for MutexSpin {} + +impl MutexSpin { + pub fn new() -> Self { + Self { + locked: UnsafeCell::new(0), + } + } + + fn lock(&self) { + let addr = self.locked.get() as *const u32; + loop { + while load_reserved(addr) == 1 {} + if store_conditional(addr, 0) { break; } + } + } + + fn unlock(&self) { + let addr = self.locked.get(); + unsafe { *addr = 0; } + } +} + +pub struct Futex { + flag: UnsafeCell, +} + +unsafe impl Send for Futex {} +unsafe impl Sync for Futex {} + +impl Futex { + pub fn new() -> Self { + Self { + flag: UnsafeCell::new(0), + } + } + + fn lock(&self) { + let addr = self.flag.get(); + if atomic_test_and_set(addr as *mut u32, 31) == 0 { + // fastpath + return; + } + // one more waiter + atomic_increment(addr as *mut u32); + loop { + if atomic_test_and_set(addr as *mut u32, 31) == 0 { + atomic_decrement(addr as *mut u32); + return; + } + let flag = unsafe { *addr }; + if flag >= 0 { continue; } + // we have to wait now + sys_futex_wait(addr, flag); + } + } + + fn unlock(&self) { + let addr = self.flag.get(); + if atomic_add_and_compare(addr as *mut u32, 0x80000000, 0) { + // no threads are waiting + return; + } + sys_futex_wake(addr); + } +} \ No newline at end of file diff --git a/user/src/syscall.rs b/user/src/syscall.rs index eecdf0968..df491b905 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -14,13 +14,11 @@ const SYSCALL_GET_TIME: usize = 169; const SYSCALL_GETPID: usize = 172; const SYSCALL_FORK: usize = 220; const SYSCALL_EXEC: usize = 221; +const SYSCALL_FUTEX: usize = 240; const SYSCALL_WAITPID: usize = 260; const SYSCALL_THREAD_CREATE: usize = 1000; const SYSCALL_GETTID: usize = 1001; const SYSCALL_WAITTID: usize = 1002; -const SYSCALL_MUTEX_CREATE: usize = 1010; -const SYSCALL_MUTEX_LOCK: usize = 1011; -const SYSCALL_MUTEX_UNLOCK: usize = 1012; const SYSCALL_SEMAPHORE_CREATE: usize = 1020; const SYSCALL_SEMAPHORE_UP: usize = 1021; const SYSCALL_SEMAPHORE_DOWN: usize = 1022; @@ -28,6 +26,10 @@ const SYSCALL_CONDVAR_CREATE: usize = 1030; const SYSCALL_CONDVAR_SIGNAL: usize = 1031; const SYSCALL_CONDVAR_WAIT: usize = 1032; +pub const FUTEX_WAIT: usize = 0; +pub const FUTEX_WAKE: usize = 1; + + fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize; unsafe { @@ -121,16 +123,12 @@ pub fn sys_waittid(tid: usize) -> isize { syscall(SYSCALL_WAITTID, [tid, 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 { - syscall(SYSCALL_MUTEX_LOCK, [id, 0, 0]) +pub fn sys_futex_wait(flag_addr: *mut i32, expect: i32) -> isize { + syscall(SYSCALL_FUTEX, [flag_addr as usize, FUTEX_WAIT, expect as usize]) } -pub fn sys_mutex_unlock(id: usize) -> isize { - syscall(SYSCALL_MUTEX_UNLOCK, [id, 0, 0]) +pub fn sys_futex_wake(flag_addr: *mut i32) -> isize { + syscall(SYSCALL_FUTEX, [flag_addr as usize, FUTEX_WAKE, 0]) } pub fn sys_semaphore_create(res_count: usize) -> isize { From 65af56a0cce04e65dad091fb9216edf308861940 Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sat, 12 Apr 2025 15:09:36 +0800 Subject: [PATCH 04/14] fix little bug of sys_futex --- os/src/syscall/sync.rs | 11 ++++++++--- os/src/task/manager.rs | 6 ------ os/src/task/mod.rs | 1 - 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index 56e256c3f..7ced9658f 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -1,5 +1,6 @@ use crate::sync::{Condvar, Mutex, Semaphore}; -use crate::task::{block_current_and_run_next, current_process, current_task, wakeup_task, block_task, take_current_task}; +use crate::task::{TaskStatus, TaskContext}; +use crate::task::{block_current_and_run_next, current_process, current_task, schedule, take_current_task, wakeup_task}; use crate::timer::{add_timer, get_time_ms}; use crate::sync::{FUTEX_WAIT, FUTEX_WAKE}; use alloc::sync::Arc; @@ -107,10 +108,14 @@ pub fn sys_futex(uaddr: *const i32, futex_op: usize, val: usize) -> isize{ if unsafe { *phys_addr == (val as i32)} { // *addr等于预期值,标记 task 为阻塞,加入 futex 等待队列 let task = take_current_task().unwrap(); - block_task(task.clone()); + let mut task_inner = task.inner_exclusive_access(); + task_inner.task_status = TaskStatus::Blocked; + let task_cx_ptr = &mut task_inner.task_cx as *mut TaskContext; + drop(task_inner); futex_q.push_back(task); futex_q.guard.unlock(); - + // switch to other task + schedule(task_cx_ptr); } else { futex_q.guard.unlock(); return 0; diff --git a/os/src/task/manager.rs b/os/src/task/manager.rs index cfe73499f..21d35ee4f 100644 --- a/os/src/task/manager.rs +++ b/os/src/task/manager.rs @@ -44,12 +44,6 @@ pub fn add_task(task: Arc) { TASK_MANAGER.exclusive_access().add(task); } -pub fn block_task(task: Arc) { - let mut task_inner = task.inner_exclusive_access(); - task_inner.task_status = TaskStatus::Blocked; - drop(task_inner); -} - pub fn wakeup_task(task: Arc) { let mut task_inner = task.inner_exclusive_access(); task_inner.task_status = TaskStatus::Ready; diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index c71406e61..d96deb666 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -27,7 +27,6 @@ pub use processor::{ }; pub use signal::SignalFlags; pub use task::{TaskControlBlock, TaskStatus}; -pub use manager::block_task; pub fn suspend_current_and_run_next() { // There must be an application running. From 6a5e2b3b1ee3bfbee9b5e1d0c1084e05b3cb7678 Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sat, 12 Apr 2025 16:34:01 +0800 Subject: [PATCH 05/14] fix little bug of sys_futex --- os/src/sync/mutex.rs | 4 ++-- os/src/syscall/sync.rs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/os/src/sync/mutex.rs b/os/src/sync/mutex.rs index dd237c26e..f35e7bb23 100644 --- a/os/src/sync/mutex.rs +++ b/os/src/sync/mutex.rs @@ -60,7 +60,7 @@ impl FutexQ { } /// 外部调用必须确保已拿到 FutexQ 的自旋锁 - pub fn pop_front(&self) -> Arc { - unsafe { &mut *self.queue.get() }.pop_front().unwrap() + pub fn pop_front(&self) -> Option> { + unsafe { &mut *self.queue.get() }.pop_front() } } \ No newline at end of file diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index 7ced9658f..cc8b2048c 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -123,8 +123,9 @@ pub fn sys_futex(uaddr: *const i32, futex_op: usize, val: usize) -> isize{ }, FUTEX_WAKE => { futex_q.guard.lock(); - let task = futex_q.pop_front(); - wakeup_task(task); + if let Some(task) = futex_q.pop_front() { + wakeup_task(task); + } futex_q.guard.unlock(); }, _ => panic!("Unsupported futex_op: {}", futex_op) From cfeda0b9cae765d1caa4751e10a034ab134c4d13 Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sat, 12 Apr 2025 17:23:01 +0800 Subject: [PATCH 06/14] fix little bug of sys_futex --- os/src/syscall/sync.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index cc8b2048c..a2ecaa891 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -1,4 +1,4 @@ -use crate::sync::{Condvar, Mutex, Semaphore}; +use crate::sync::{Condvar, Mutex, Semaphore, FutexQ}; use crate::task::{TaskStatus, TaskContext}; use crate::task::{block_current_and_run_next, current_process, current_task, schedule, take_current_task, wakeup_task}; use crate::timer::{add_timer, get_time_ms}; @@ -95,13 +95,16 @@ pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize { /// 封装在 Futex 方法中,不应直接调用 pub fn sys_futex(uaddr: *const i32, futex_op: usize, val: usize) -> isize{ let process = current_process(); - let process_inner = process.inner_exclusive_access(); - let futex_q = process_inner.futex_queues.get(&(uaddr as usize)).unwrap(); + let mut process_inner = process.inner_exclusive_access(); let phys_addr = process_inner .memory_set .translate_va((uaddr as usize).into()) .unwrap() .0 as *const i32; + // 如果 Futex 第一次调用 sys_futex,则插入新的队列 + let futex_q = process_inner.futex_queues + .entry(uaddr as usize) + .or_insert(FutexQ::new()); match futex_op { FUTEX_WAIT => { futex_q.guard.lock(); @@ -115,6 +118,7 @@ pub fn sys_futex(uaddr: *const i32, futex_op: usize, val: usize) -> isize{ futex_q.push_back(task); futex_q.guard.unlock(); // switch to other task + drop(process_inner); schedule(task_cx_ptr); } else { futex_q.guard.unlock(); From c49dceb9b0329393718b3e2d284f3e5ca9a2b63d Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sat, 12 Apr 2025 19:08:40 +0800 Subject: [PATCH 07/14] refactor(condvar): reconstruct Condvar and move it from os crate to user crate - Delete syscalls of Condvar - Add new Condvar based on sys_futex to user lib Todo: Examine correctness of Mutex and Condvar --- os/src/sync/condvar.rs | 39 ------------------------------------- os/src/sync/mod.rs | 2 -- os/src/syscall/mod.rs | 6 ------ os/src/syscall/sync.rs | 42 +--------------------------------------- os/src/task/process.rs | 5 +---- user/src/sync/condvar.rs | 32 ++++++++++++++++++++++++++++++ user/src/sync/mod.rs | 1 + user/src/sync/mutex.rs | 8 ++++---- 8 files changed, 39 insertions(+), 96 deletions(-) delete mode 100644 os/src/sync/condvar.rs create mode 100644 user/src/sync/condvar.rs diff --git a/os/src/sync/condvar.rs b/os/src/sync/condvar.rs deleted file mode 100644 index baba3cb92..000000000 --- a/os/src/sync/condvar.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::sync::{Mutex, UPSafeCell}; -use crate::task::{block_current_and_run_next, current_task, wakeup_task, TaskControlBlock}; -use alloc::{collections::VecDeque, sync::Arc}; - -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() { - wakeup_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 ed5d59c49..bb0630fd7 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -1,9 +1,7 @@ -mod condvar; mod mutex; mod semaphore; mod up; -pub use condvar::Condvar; pub use mutex::{FUTEX_WAIT, FUTEX_WAKE}; pub use mutex::{Mutex, MutexSpin, FutexQ}; pub use semaphore::Semaphore; diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index a7e4c57a1..1a89567f0 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -20,9 +20,6 @@ pub const SYSCALL_WAITTID: usize = 1002; pub const SYSCALL_SEMAPHORE_CREATE: usize = 1020; pub const SYSCALL_SEMAPHORE_UP: usize = 1021; pub const SYSCALL_SEMAPHORE_DOWN: usize = 1022; -pub const SYSCALL_CONDVAR_CREATE: usize = 1030; -pub const SYSCALL_CONDVAR_SIGNAL: usize = 1031; -pub const SYSCALL_CONDVAR_WAIT: usize = 1032; mod fs; mod process; @@ -58,9 +55,6 @@ pub fn syscall_handler(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(), - 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 a2ecaa891..e918e4f37 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -1,4 +1,4 @@ -use crate::sync::{Condvar, Mutex, Semaphore, FutexQ}; +use crate::sync::{Mutex, Semaphore, FutexQ}; use crate::task::{TaskStatus, TaskContext}; use crate::task::{block_current_and_run_next, current_process, current_task, schedule, take_current_task, wakeup_task}; use crate::timer::{add_timer, get_time_ms}; @@ -52,46 +52,6 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize { 0 } -pub fn sys_condvar_create() -> 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 -} - /// 封装在 Futex 方法中,不应直接调用 pub fn sys_futex(uaddr: *const i32, futex_op: usize, val: usize) -> isize{ let process = current_process(); diff --git a/os/src/task/process.rs b/os/src/task/process.rs index a7d713a8f..682955d7b 100644 --- a/os/src/task/process.rs +++ b/os/src/task/process.rs @@ -5,7 +5,7 @@ use super::{add_task, SignalFlags}; use super::{pid_alloc, PidHandle}; use crate::fs::{File, Stdin, Stdout}; use crate::mm::{translated_refmut, MemorySet, KERNEL_SPACE}; -use crate::sync::{Condvar, Mutex, Semaphore, UPSafeCell, FutexQ}; +use crate::sync::{Semaphore, UPSafeCell, FutexQ}; use crate::trap::{trap_handler, TrapContext}; use alloc::string::String; use alloc::sync::{Arc, Weak}; @@ -33,7 +33,6 @@ pub struct ProcessControlBlockInner { pub task_res_allocator: RecycleAllocator, pub futex_queues: BTreeMap, pub semaphore_list: Vec>>, - pub condvar_list: Vec>>, } impl ProcessControlBlockInner { @@ -100,7 +99,6 @@ impl ProcessControlBlock { task_res_allocator: RecycleAllocator::new(), futex_queues: BTreeMap::new(), semaphore_list: Vec::new(), - condvar_list: Vec::new(), }) }, }); @@ -219,7 +217,6 @@ impl ProcessControlBlock { task_res_allocator: RecycleAllocator::new(), futex_queues: BTreeMap::new(), semaphore_list: Vec::new(), - condvar_list: Vec::new(), }) }, }); diff --git a/user/src/sync/condvar.rs b/user/src/sync/condvar.rs new file mode 100644 index 000000000..f8ab3654a --- /dev/null +++ b/user/src/sync/condvar.rs @@ -0,0 +1,32 @@ +use super::*; +use core::cell::UnsafeCell; +use crate::syscall::{sys_futex_wait, sys_futex_wake}; + +pub struct Condvar { + flag: UnsafeCell, +} + +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + +impl Condvar { + pub fn new() -> Self { + Self { + flag: UnsafeCell::new(0) + } + } + + pub fn wait(&self, mutex: &MutexSpin) { + mutex.unlock(); + let addr = self.flag.get(); + let val = unsafe { *addr }; + sys_futex_wait(addr, val); + mutex.lock(); + } + + pub fn notify_one(&self) { + let addr = self.flag.get(); + atomic_increment(addr as *mut u32); + sys_futex_wake(addr); + } +} \ No newline at end of file diff --git a/user/src/sync/mod.rs b/user/src/sync/mod.rs index 514a18fc3..3307dd011 100644 --- a/user/src/sync/mod.rs +++ b/user/src/sync/mod.rs @@ -1,4 +1,5 @@ mod mutex; +mod condvar; pub use mutex::*; diff --git a/user/src/sync/mutex.rs b/user/src/sync/mutex.rs index 33863e3e4..49bffd47c 100644 --- a/user/src/sync/mutex.rs +++ b/user/src/sync/mutex.rs @@ -16,7 +16,7 @@ impl MutexSpin { } } - fn lock(&self) { + pub fn lock(&self) { let addr = self.locked.get() as *const u32; loop { while load_reserved(addr) == 1 {} @@ -24,7 +24,7 @@ impl MutexSpin { } } - fn unlock(&self) { + pub fn unlock(&self) { let addr = self.locked.get(); unsafe { *addr = 0; } } @@ -44,7 +44,7 @@ impl Futex { } } - fn lock(&self) { + pub fn lock(&self) { let addr = self.flag.get(); if atomic_test_and_set(addr as *mut u32, 31) == 0 { // fastpath @@ -64,7 +64,7 @@ impl Futex { } } - fn unlock(&self) { + pub fn unlock(&self) { let addr = self.flag.get(); if atomic_add_and_compare(addr as *mut u32, 0x80000000, 0) { // no threads are waiting From 219648d3e04d60f2a585bc131a0e84a62291b015 Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sat, 12 Apr 2025 22:03:26 +0800 Subject: [PATCH 08/14] fix(MutexSpin): fix functional error of method Store in , not . --- os/src/lib.rs | 24 ------------------------ os/src/sync/mod.rs | 7 ++++++- os/src/sync/mutex.rs | 2 +- user/src/bin/adder_mutex_blocking.rs | 11 +++++++---- user/src/bin/adder_mutex_spin.rs | 11 +++++++---- user/src/bin/barrier_condvar.rs | 20 ++++++++++---------- user/src/bin/condsync_condvar.rs | 24 ++++++++++++------------ user/src/bin/condsync_sem.rs | 20 +++++++++++--------- user/src/bin/eisenberg.rs | 4 +--- user/src/bin/phil_din_mutex.rs | 15 +++++++++------ user/src/lib.rs | 10 +--------- user/src/sync/mod.rs | 1 + user/src/sync/mutex.rs | 4 ++-- user/src/syscall.rs | 17 +---------------- 14 files changed, 69 insertions(+), 101 deletions(-) delete mode 100644 os/src/lib.rs diff --git a/os/src/lib.rs b/os/src/lib.rs deleted file mode 100644 index 13de31993..000000000 --- a/os/src/lib.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![no_std] -#![feature(alloc_error_handler)] - -extern crate alloc; - -#[macro_use] -extern crate bitflags; - -#[path = "boards/qemu.rs"] -mod board; - -#[macro_use] -pub mod console; -pub mod config; -pub mod drivers; -pub mod fs; -pub mod lang_items; -pub mod mm; -pub mod sbi; -pub mod sync; -pub mod syscall; -pub mod task; -pub mod timer; -pub mod trap; \ No newline at end of file diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs index bb0630fd7..a1c8096a6 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -3,7 +3,7 @@ mod semaphore; mod up; pub use mutex::{FUTEX_WAIT, FUTEX_WAKE}; -pub use mutex::{Mutex, MutexSpin, FutexQ}; +pub use mutex::{Mutex, FutexQ}; pub use semaphore::Semaphore; pub use up::UPSafeCell; @@ -22,6 +22,7 @@ pub fn load_reserved(addr: *const u32) -> u32 { /// return true if successfully modify `addr` in memory #[inline(always)] +#[allow(unused)] pub fn store_conditional(addr: *const u32, val: u32) -> bool { let res: u32; unsafe { @@ -36,6 +37,7 @@ pub fn store_conditional(addr: *const u32, val: u32) -> bool { } #[inline(always)] +#[allow(unused)] pub fn atomic_increment(addr: *mut u32) { loop { let val = load_reserved(addr); @@ -44,6 +46,7 @@ pub fn atomic_increment(addr: *mut u32) { } #[inline(always)] +#[allow(unused)] pub fn atomic_decrement(addr: *mut u32) { loop { let val = load_reserved(addr); @@ -52,6 +55,7 @@ pub fn atomic_decrement(addr: *mut u32) { } #[inline(always)] +#[allow(unused)] pub fn atomic_test_and_set(addr: *mut u32, bit: u32) -> u32 { loop { let val = load_reserved(addr); @@ -62,6 +66,7 @@ pub fn atomic_test_and_set(addr: *mut u32, bit: u32) -> u32 { /// 原子地使 `(addr)` 自加 `addend`,并比较结果与 `expected` 是否相等。 /// 相等则返回 `true` #[inline(always)] +#[allow(unused)] pub fn atomic_add_and_compare(addr: *mut u32, addend: u32, expected: u32) -> bool { loop { let val = load_reserved(addr); diff --git a/os/src/sync/mutex.rs b/os/src/sync/mutex.rs index f35e7bb23..9fe161f6d 100644 --- a/os/src/sync/mutex.rs +++ b/os/src/sync/mutex.rs @@ -30,7 +30,7 @@ impl Mutex for MutexSpin { let addr = self.locked.get() as *const u32; loop { while load_reserved(addr) == 1 {} - if store_conditional(addr, 0) { break; } + if store_conditional(addr, 1) { return; } } } diff --git a/user/src/bin/adder_mutex_blocking.rs b/user/src/bin/adder_mutex_blocking.rs index 7fcb80bd8..582598f82 100644 --- a/user/src/bin/adder_mutex_blocking.rs +++ b/user/src/bin/adder_mutex_blocking.rs @@ -8,12 +8,16 @@ extern crate alloc; use alloc::vec::Vec; use core::ptr::addr_of_mut; use user_lib::{exit, get_time, thread_create, waittid}; -use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; +use user_lib::Futex; +use lazy_static::lazy_static; static mut A: usize = 0; const PER_THREAD_DEFAULT: usize = 10000; const THREAD_COUNT_DEFAULT: usize = 16; static mut PER_THREAD: usize = 0; +lazy_static! { + static ref futex: Futex = Futex::new(); +} unsafe fn critical_section(t: &mut usize) { let a = addr_of_mut!(A); @@ -26,9 +30,9 @@ unsafe fn critical_section(t: &mut usize) { unsafe fn f() -> ! { let mut t = 2usize; for _ in 0..PER_THREAD { - mutex_lock(0); + futex.lock(); critical_section(&mut t); - mutex_unlock(0); + futex.unlock(); } exit(t as i32) } @@ -48,7 +52,6 @@ pub fn main(argc: usize, argv: &[&str]) -> 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, 0) as usize); diff --git a/user/src/bin/adder_mutex_spin.rs b/user/src/bin/adder_mutex_spin.rs index f5750af86..9f7fb50bf 100644 --- a/user/src/bin/adder_mutex_spin.rs +++ b/user/src/bin/adder_mutex_spin.rs @@ -8,12 +8,16 @@ extern crate alloc; use alloc::vec::Vec; use core::ptr::addr_of_mut; use user_lib::{exit, get_time, thread_create, waittid}; -use user_lib::{mutex_create, mutex_lock, mutex_unlock}; +use user_lib::MutexSpin; +use lazy_static::lazy_static; static mut A: usize = 0; const PER_THREAD_DEFAULT: usize = 10000; const THREAD_COUNT_DEFAULT: usize = 16; static mut PER_THREAD: usize = 0; +lazy_static! { + static ref spinlock: MutexSpin = MutexSpin::new(); +} unsafe fn critical_section(t: &mut usize) { let a = addr_of_mut!(A); @@ -27,9 +31,9 @@ unsafe fn critical_section(t: &mut usize) { unsafe fn f() -> ! { let mut t = 2usize; for _ in 0..PER_THREAD { - mutex_lock(0); + spinlock.lock(); critical_section(&mut t); - mutex_unlock(0); + spinlock.unlock(); } exit(t as i32) } @@ -49,7 +53,6 @@ pub fn main(argc: usize, argv: &[&str]) -> 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, 0) as usize); diff --git a/user/src/bin/barrier_condvar.rs b/user/src/bin/barrier_condvar.rs index 715777231..d97fca7ba 100644 --- a/user/src/bin/barrier_condvar.rs +++ b/user/src/bin/barrier_condvar.rs @@ -9,28 +9,28 @@ use alloc::vec::Vec; use core::cell::UnsafeCell; use lazy_static::*; use user_lib::{ - condvar_create, condvar_signal, condvar_wait, exit, mutex_create, mutex_lock, mutex_unlock, + exit, MutexSpin, Condvar, thread_create, waittid, }; const THREAD_NUM: usize = 3; struct Barrier { - mutex_id: usize, - condvar_id: usize, + mutex: MutexSpin, + condvar: Condvar, count: UnsafeCell, } impl Barrier { pub fn new() -> Self { Self { - mutex_id: mutex_create() as usize, - condvar_id: condvar_create() as usize, + mutex: MutexSpin::new(), + condvar: Condvar::new(), count: UnsafeCell::new(0), } } pub fn block(&self) { - mutex_lock(self.mutex_id); + self.mutex.lock(); let count = self.count.get(); // SAFETY: Here, the accesses of the count is in the // critical section protected by the mutex. @@ -38,12 +38,12 @@ impl Barrier { *count = *count + 1; } if unsafe { *count } == THREAD_NUM { - condvar_signal(self.condvar_id); + self.condvar.notify_one(); } else { - condvar_wait(self.condvar_id, self.mutex_id); - condvar_signal(self.condvar_id); + self.condvar.wait(&self.mutex); + self.condvar.notify_one(); } - mutex_unlock(self.mutex_id); + self.mutex.unlock(); } } diff --git a/user/src/bin/condsync_condvar.rs b/user/src/bin/condsync_condvar.rs index 51802c67e..eb7d4891a 100644 --- a/user/src/bin/condsync_condvar.rs +++ b/user/src/bin/condsync_condvar.rs @@ -9,42 +9,42 @@ extern crate alloc; use alloc::vec; use user_lib::exit; use user_lib::{ - condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock, + MutexSpin, Condvar }; use user_lib::{sleep, thread_create, waittid}; +use lazy_static::lazy_static; static mut A: usize = 0; -const CONDVAR_ID: usize = 0; -const MUTEX_ID: usize = 0; +lazy_static! { + static ref mutex: MutexSpin = MutexSpin::new(); + static ref condvar: Condvar = Condvar::new(); +} unsafe fn first() -> ! { sleep(10); println!("First work, Change A --> 1 and wakeup Second"); - mutex_lock(MUTEX_ID); + mutex.lock(); A = 1; - condvar_signal(CONDVAR_ID); - mutex_unlock(MUTEX_ID); + condvar.notify_one(); + mutex.unlock(); exit(0) } unsafe fn second() -> ! { println!("Second want to continue,but need to wait A=1"); - mutex_lock(MUTEX_ID); + mutex.lock(); while A == 0 { println!("Second: A is {}", &raw mut A as usize); - condvar_wait(CONDVAR_ID, MUTEX_ID); + condvar.wait(&mutex); } println!("A is {}, Second can work now", &raw mut A as usize); - mutex_unlock(MUTEX_ID); + mutex.unlock(); 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 threads = vec![ thread_create(first as usize, 0), diff --git a/user/src/bin/condsync_sem.rs b/user/src/bin/condsync_sem.rs index bdea221a8..6385e4e53 100644 --- a/user/src/bin/condsync_sem.rs +++ b/user/src/bin/condsync_sem.rs @@ -9,35 +9,38 @@ extern crate alloc; use alloc::vec; use user_lib::exit; use user_lib::{ - mutex_blocking_create, mutex_lock, mutex_unlock, semaphore_create, semaphore_down, semaphore_up, + MutexSpin, Condvar, semaphore_create, semaphore_down, semaphore_up, }; use user_lib::{sleep, thread_create, waittid}; +use lazy_static::lazy_static; static mut A: usize = 0; - const SEM_ID: usize = 0; -const MUTEX_ID: usize = 0; +lazy_static! { + static ref mutex: MutexSpin = MutexSpin::new(); + static ref condvar: Condvar = Condvar::new(); +} unsafe fn first() -> ! { sleep(10); println!("First work, Change A --> 1 and wakeup Second"); - mutex_lock(MUTEX_ID); + mutex.lock(); A = 1; semaphore_up(SEM_ID); - mutex_unlock(MUTEX_ID); + mutex.unlock(); exit(0) } unsafe fn second() -> ! { println!("Second want to continue,but need to wait A=1"); loop { - mutex_lock(MUTEX_ID); + mutex.lock(); if A == 0 { println!("Second: A is {}", &raw mut A as usize); - mutex_unlock(MUTEX_ID); + mutex.unlock(); semaphore_down(SEM_ID); } else { - mutex_unlock(MUTEX_ID); + mutex.unlock(); break; } } @@ -49,7 +52,6 @@ unsafe fn second() -> ! { pub fn main() -> i32 { // create semaphore & mutex assert_eq!(semaphore_create(0) as usize, SEM_ID); - assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); // create threads let threads = vec![ thread_create(first as usize, 0), diff --git a/user/src/bin/eisenberg.rs b/user/src/bin/eisenberg.rs index 49a1d4549..6c9bdcb4d 100644 --- a/user/src/bin/eisenberg.rs +++ b/user/src/bin/eisenberg.rs @@ -7,9 +7,7 @@ extern crate alloc; extern crate core; use alloc::vec::Vec; -use core::{ - sync::atomic::{AtomicUsize, Ordering}, -}; +use core::sync::atomic::{AtomicUsize, Ordering}; use user_lib::{exit, sleep, thread_create, waittid}; const N: usize = 2; diff --git a/user/src/bin/phil_din_mutex.rs b/user/src/bin/phil_din_mutex.rs index 8e7b56677..f4e18e3ad 100644 --- a/user/src/bin/phil_din_mutex.rs +++ b/user/src/bin/phil_din_mutex.rs @@ -8,13 +8,17 @@ extern crate alloc; use alloc::vec::Vec; use user_lib::{exit, get_time, sleep}; -use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; +use user_lib::MutexSpin; use user_lib::{thread_create, waittid}; +use lazy_static::lazy_static; const N: usize = 5; const ROUND: usize = 4; // A round: think -> wait for forks -> eat const GRAPH_SCALE: usize = 100; +lazy_static! { + static ref mutex: [MutexSpin; N] = [MutexSpin::new(), MutexSpin::new(), MutexSpin::new(), MutexSpin::new(), MutexSpin::new()]; +} fn get_time_u() -> usize { get_time() as usize @@ -47,8 +51,8 @@ fn philosopher_dining_problem(id: *const usize) { THINK[id][2 * round + 1] = get_time_u(); } // wait for forks - mutex_lock(min); - mutex_lock(max); + mutex[min].lock(); + mutex[max].lock(); // eating unsafe { EAT[id][2 * round] = get_time_u(); @@ -57,8 +61,8 @@ fn philosopher_dining_problem(id: *const usize) { unsafe { EAT[id][2 * round + 1] = get_time_u(); } - mutex_unlock(max); - mutex_unlock(min); + mutex[max].unlock(); + mutex[min].unlock(); } exit(0) } @@ -69,7 +73,6 @@ pub fn main() -> i32 { let ids: Vec<_> = (0..N).collect(); let start = get_time_u(); for i in 0..N { - assert_eq!(mutex_blocking_create(), i as isize); v.push(thread_create( philosopher_dining_problem as usize, &ids.as_slice()[i] as *const _ as usize, diff --git a/user/src/lib.rs b/user/src/lib.rs index 5e93c35f5..d8a5a70b7 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -15,6 +15,7 @@ extern crate bitflags; use alloc::vec::Vec; use buddy_system_allocator::LockedHeap; use syscall::*; +pub use sync::*; const USER_HEAP_SIZE: usize = 32768; @@ -184,15 +185,6 @@ 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() -} -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); -} #[macro_export] macro_rules! vstore { diff --git a/user/src/sync/mod.rs b/user/src/sync/mod.rs index 3307dd011..b4c638f27 100644 --- a/user/src/sync/mod.rs +++ b/user/src/sync/mod.rs @@ -2,6 +2,7 @@ mod mutex; mod condvar; pub use mutex::*; +pub use condvar::*; #[inline(always)] pub fn load_reserved(addr: *const u32) -> u32 { diff --git a/user/src/sync/mutex.rs b/user/src/sync/mutex.rs index 49bffd47c..648c13987 100644 --- a/user/src/sync/mutex.rs +++ b/user/src/sync/mutex.rs @@ -1,6 +1,6 @@ use super::*; use core::cell::UnsafeCell; -use crate::syscall::{self, sys_futex_wait, sys_futex_wake}; +use crate::syscall::{sys_futex_wait, sys_futex_wake}; pub struct MutexSpin { locked: UnsafeCell, @@ -20,7 +20,7 @@ impl MutexSpin { let addr = self.locked.get() as *const u32; loop { while load_reserved(addr) == 1 {} - if store_conditional(addr, 0) { break; } + if store_conditional(addr, 1) { return; } } } diff --git a/user/src/syscall.rs b/user/src/syscall.rs index df491b905..04337d1d0 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -22,9 +22,6 @@ const SYSCALL_WAITTID: usize = 1002; 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; pub const FUTEX_WAIT: usize = 0; pub const FUTEX_WAKE: usize = 1; @@ -141,16 +138,4 @@ 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() -> isize { - syscall(SYSCALL_CONDVAR_CREATE, [0, 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]) -} +} \ No newline at end of file From fb52c11a25828ba9c6d8639034c3a48c2d4137cc Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sun, 13 Apr 2025 21:39:36 +0800 Subject: [PATCH 09/14] use futex in adder_mutex_blocking.rs --- user/src/bin/adder_mutex_blocking.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user/src/bin/adder_mutex_blocking.rs b/user/src/bin/adder_mutex_blocking.rs index 582598f82..53773fc6e 100644 --- a/user/src/bin/adder_mutex_blocking.rs +++ b/user/src/bin/adder_mutex_blocking.rs @@ -16,13 +16,13 @@ const PER_THREAD_DEFAULT: usize = 10000; const THREAD_COUNT_DEFAULT: usize = 16; static mut PER_THREAD: usize = 0; lazy_static! { - static ref futex: Futex = Futex::new(); + static ref mutex: Futex = Futex::new(); } unsafe fn critical_section(t: &mut usize) { let a = addr_of_mut!(A); let cur = a.read_volatile(); - for _ in 0..500 { + for _ in 0..5 { *t = (*t) * (*t) % 10007; } a.write_volatile(cur + 1); @@ -30,9 +30,9 @@ unsafe fn critical_section(t: &mut usize) { unsafe fn f() -> ! { let mut t = 2usize; for _ in 0..PER_THREAD { - futex.lock(); + mutex.lock(); critical_section(&mut t); - futex.unlock(); + mutex.unlock(); } exit(t as i32) } From 7498f19152db747b115c62f083e60ab3aae3f491 Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sun, 13 Apr 2025 23:49:13 +0800 Subject: [PATCH 10/14] fix(sync): fix atomic_test_and_set - Return val & (1 << bit) --- user/src/bin/adder_mutex_blocking.rs | 11 +++++++---- user/src/sync/mod.rs | 6 +++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/user/src/bin/adder_mutex_blocking.rs b/user/src/bin/adder_mutex_blocking.rs index 53773fc6e..609f5848e 100644 --- a/user/src/bin/adder_mutex_blocking.rs +++ b/user/src/bin/adder_mutex_blocking.rs @@ -22,17 +22,20 @@ lazy_static! { unsafe fn critical_section(t: &mut usize) { let a = addr_of_mut!(A); let cur = a.read_volatile(); - for _ in 0..5 { + for _ in 0..500 { *t = (*t) * (*t) % 10007; } a.write_volatile(cur + 1); } -unsafe fn f() -> ! { +unsafe fn f(_id: usize) -> ! { let mut t = 2usize; for _ in 0..PER_THREAD { + // println!("Thread {} is getting lock...", id); mutex.lock(); + // println!("Thread {} already get lock", id); critical_section(&mut t); mutex.unlock(); + // println!("Thread {} release lock", id); } exit(t as i32) } @@ -53,8 +56,8 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 { let start = get_time(); let mut v = Vec::new(); - for _ in 0..thread_count { - v.push(thread_create(f as usize, 0) as usize); + for id in 0..thread_count { + v.push(thread_create(f as usize, id) as usize); } for tid in v.into_iter() { waittid(tid); diff --git a/user/src/sync/mod.rs b/user/src/sync/mod.rs index b4c638f27..006fc8a5d 100644 --- a/user/src/sync/mod.rs +++ b/user/src/sync/mod.rs @@ -48,11 +48,15 @@ pub fn atomic_decrement(addr: *mut u32) { } } +/// 原子地测试 `*addr & (1 << bit)` 并设置 `(addr)` 为 `*addr | (1 << bit)`. +/// 返回测试结果,为 0 说明对应位原本是 0. #[inline(always)] pub fn atomic_test_and_set(addr: *mut u32, bit: u32) -> u32 { loop { let val = load_reserved(addr); - if store_conditional(addr, val | (1 << bit)) { return val; } + if store_conditional(addr, val | (1 << bit)) { + return val & (1 << bit); + } } } From 673e5b5b8e838a47fba918bf759e7a3fc8c0b2b0 Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Thu, 17 Apr 2025 18:53:25 +0800 Subject: [PATCH 11/14] fix type of param in store_conditional --- os/src/sync/mod.rs | 2 +- os/src/sync/mutex.rs | 2 +- user/src/sync/mod.rs | 2 +- user/src/sync/mutex.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs index a1c8096a6..92229d24f 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -23,7 +23,7 @@ pub fn load_reserved(addr: *const u32) -> u32 { /// return true if successfully modify `addr` in memory #[inline(always)] #[allow(unused)] -pub fn store_conditional(addr: *const u32, val: u32) -> bool { +pub fn store_conditional(addr: *mut u32, val: u32) -> bool { let res: u32; unsafe { core::arch::asm!( diff --git a/os/src/sync/mutex.rs b/os/src/sync/mutex.rs index 9fe161f6d..cb512229f 100644 --- a/os/src/sync/mutex.rs +++ b/os/src/sync/mutex.rs @@ -27,7 +27,7 @@ impl MutexSpin { impl Mutex for MutexSpin { fn lock(&self) { - let addr = self.locked.get() as *const u32; + let addr = self.locked.get(); loop { while load_reserved(addr) == 1 {} if store_conditional(addr, 1) { return; } diff --git a/user/src/sync/mod.rs b/user/src/sync/mod.rs index 006fc8a5d..e10a0794b 100644 --- a/user/src/sync/mod.rs +++ b/user/src/sync/mod.rs @@ -19,7 +19,7 @@ pub fn load_reserved(addr: *const u32) -> u32 { /// return true if successfully modify `addr` in memory #[inline(always)] -pub fn store_conditional(addr: *const u32, val: u32) -> bool { +pub fn store_conditional(addr: *mut u32, val: u32) -> bool { let res: u32; unsafe { core::arch::asm!( diff --git a/user/src/sync/mutex.rs b/user/src/sync/mutex.rs index 648c13987..30961ac74 100644 --- a/user/src/sync/mutex.rs +++ b/user/src/sync/mutex.rs @@ -17,7 +17,7 @@ impl MutexSpin { } pub fn lock(&self) { - let addr = self.locked.get() as *const u32; + let addr = self.locked.get(); loop { while load_reserved(addr) == 1 {} if store_conditional(addr, 1) { return; } From 3ac7194321e537a4f1a9c3fec333054d045c7ca5 Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sat, 19 Apr 2025 11:41:42 +0800 Subject: [PATCH 12/14] refactor(semaphore): reconstruct semaphore based on sys_futex - Move semaphore module from kernel to user lib - Delete semaphore syscalls --- os/src/sync/mod.rs | 2 -- os/src/sync/semaphore.rs | 45 ------------------------------------ os/src/syscall/mod.rs | 6 ----- os/src/syscall/sync.rs | 42 +-------------------------------- os/src/task/process.rs | 5 +--- user/src/bin/condsync_sem.rs | 12 ++++------ user/src/bin/mpsc_sem.rs | 32 ++++++++++++------------- user/src/bin/sync_sem.rs | 14 +++++------ user/src/lib.rs | 10 -------- user/src/sync/mod.rs | 2 ++ user/src/sync/semaphore.rs | 35 ++++++++++++++++++++++++++++ user/src/syscall.rs | 15 ------------ 12 files changed, 67 insertions(+), 153 deletions(-) delete mode 100644 os/src/sync/semaphore.rs create mode 100644 user/src/sync/semaphore.rs diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs index 92229d24f..4b2bd5a5c 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -1,10 +1,8 @@ mod mutex; -mod semaphore; mod up; pub use mutex::{FUTEX_WAIT, FUTEX_WAKE}; pub use mutex::{Mutex, FutexQ}; -pub use semaphore::Semaphore; pub use up::UPSafeCell; #[inline(always)] diff --git a/os/src/sync/semaphore.rs b/os/src/sync/semaphore.rs deleted file mode 100644 index dfbd12bf7..000000000 --- a/os/src/sync/semaphore.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::sync::UPSafeCell; -use crate::task::{block_current_and_run_next, current_task, wakeup_task, TaskControlBlock}; -use alloc::{collections::VecDeque, sync::Arc}; - -pub struct Semaphore { - pub inner: UPSafeCell, -} - -pub struct SemaphoreInner { - pub count: isize, - pub wait_queue: VecDeque>, -} - -impl Semaphore { - pub fn new(res_count: usize) -> Self { - Self { - inner: unsafe { - UPSafeCell::new(SemaphoreInner { - count: res_count as isize, - wait_queue: VecDeque::new(), - }) - }, - } - } - - pub fn up(&self) { - let mut inner = self.inner.exclusive_access(); - inner.count += 1; - if inner.count <= 0 { - if let Some(task) = inner.wait_queue.pop_front() { - wakeup_task(task); - } - } - } - - pub fn down(&self) { - let mut inner = self.inner.exclusive_access(); - inner.count -= 1; - if inner.count < 0 { - inner.wait_queue.push_back(current_task().unwrap()); - drop(inner); - block_current_and_run_next(); - } - } -} diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 1a89567f0..3da11327b 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -17,9 +17,6 @@ pub const SYSCALL_WAITPID: usize = 260; pub const SYSCALL_THREAD_CREATE: usize = 1000; pub const SYSCALL_GETTID: usize = 1001; pub const SYSCALL_WAITTID: usize = 1002; -pub const SYSCALL_SEMAPHORE_CREATE: usize = 1020; -pub const SYSCALL_SEMAPHORE_UP: usize = 1021; -pub const SYSCALL_SEMAPHORE_DOWN: usize = 1022; mod fs; mod process; @@ -52,9 +49,6 @@ pub fn syscall_handler(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_THREAD_CREATE => sys_thread_create(args[0], args[1]), SYSCALL_GETTID => sys_gettid(), SYSCALL_WAITTID => sys_waittid(args[0]) as 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]), _ => panic!("Unsupported syscall_id: {}", syscall_id), } } diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index e918e4f37..2433595bf 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -1,9 +1,8 @@ -use crate::sync::{Mutex, Semaphore, FutexQ}; +use crate::sync::{Mutex, FutexQ}; use crate::task::{TaskStatus, TaskContext}; use crate::task::{block_current_and_run_next, current_process, current_task, schedule, take_current_task, wakeup_task}; use crate::timer::{add_timer, get_time_ms}; use crate::sync::{FUTEX_WAIT, FUTEX_WAKE}; -use alloc::sync::Arc; pub fn sys_sleep(ms: usize) -> isize { let expire_ms = get_time_ms() + ms; @@ -13,45 +12,6 @@ pub fn sys_sleep(ms: usize) -> isize { 0 } -pub fn sys_semaphore_create(res_count: usize) -> isize { - let process = current_process(); - let mut process_inner = process.inner_exclusive_access(); - let id = if let Some(id) = process_inner - .semaphore_list - .iter() - .enumerate() - .find(|(_, item)| item.is_none()) - .map(|(id, _)| id) - { - process_inner.semaphore_list[id] = Some(Arc::new(Semaphore::new(res_count))); - id - } else { - process_inner - .semaphore_list - .push(Some(Arc::new(Semaphore::new(res_count)))); - process_inner.semaphore_list.len() - 1 - }; - id as isize -} - -pub fn sys_semaphore_up(sem_id: usize) -> isize { - let process = current_process(); - let process_inner = process.inner_exclusive_access(); - let sem = Arc::clone(process_inner.semaphore_list[sem_id].as_ref().unwrap()); - drop(process_inner); - sem.up(); - 0 -} - -pub fn sys_semaphore_down(sem_id: usize) -> isize { - let process = current_process(); - let process_inner = process.inner_exclusive_access(); - let sem = Arc::clone(process_inner.semaphore_list[sem_id].as_ref().unwrap()); - drop(process_inner); - sem.down(); - 0 -} - /// 封装在 Futex 方法中,不应直接调用 pub fn sys_futex(uaddr: *const i32, futex_op: usize, val: usize) -> isize{ let process = current_process(); diff --git a/os/src/task/process.rs b/os/src/task/process.rs index 682955d7b..c0783fb5c 100644 --- a/os/src/task/process.rs +++ b/os/src/task/process.rs @@ -5,7 +5,7 @@ use super::{add_task, SignalFlags}; use super::{pid_alloc, PidHandle}; use crate::fs::{File, Stdin, Stdout}; use crate::mm::{translated_refmut, MemorySet, KERNEL_SPACE}; -use crate::sync::{Semaphore, UPSafeCell, FutexQ}; +use crate::sync::{UPSafeCell, FutexQ}; use crate::trap::{trap_handler, TrapContext}; use alloc::string::String; use alloc::sync::{Arc, Weak}; @@ -32,7 +32,6 @@ pub struct ProcessControlBlockInner { pub tasks: Vec>>, pub task_res_allocator: RecycleAllocator, pub futex_queues: BTreeMap, - pub semaphore_list: Vec>>, } impl ProcessControlBlockInner { @@ -98,7 +97,6 @@ impl ProcessControlBlock { tasks: Vec::new(), task_res_allocator: RecycleAllocator::new(), futex_queues: BTreeMap::new(), - semaphore_list: Vec::new(), }) }, }); @@ -216,7 +214,6 @@ impl ProcessControlBlock { tasks: Vec::new(), task_res_allocator: RecycleAllocator::new(), futex_queues: BTreeMap::new(), - semaphore_list: Vec::new(), }) }, }); diff --git a/user/src/bin/condsync_sem.rs b/user/src/bin/condsync_sem.rs index 6385e4e53..c6be357c6 100644 --- a/user/src/bin/condsync_sem.rs +++ b/user/src/bin/condsync_sem.rs @@ -9,16 +9,15 @@ extern crate alloc; use alloc::vec; use user_lib::exit; use user_lib::{ - MutexSpin, Condvar, semaphore_create, semaphore_down, semaphore_up, + MutexSpin, Semaphore, }; use user_lib::{sleep, thread_create, waittid}; use lazy_static::lazy_static; static mut A: usize = 0; -const SEM_ID: usize = 0; lazy_static! { static ref mutex: MutexSpin = MutexSpin::new(); - static ref condvar: Condvar = Condvar::new(); + static ref sem: Semaphore = Semaphore::new(0); } unsafe fn first() -> ! { @@ -26,7 +25,8 @@ unsafe fn first() -> ! { println!("First work, Change A --> 1 and wakeup Second"); mutex.lock(); A = 1; - semaphore_up(SEM_ID); + println!("First is going to sem.post()"); + sem.post(); mutex.unlock(); exit(0) } @@ -38,7 +38,7 @@ unsafe fn second() -> ! { if A == 0 { println!("Second: A is {}", &raw mut A as usize); mutex.unlock(); - semaphore_down(SEM_ID); + sem.wait(); } else { mutex.unlock(); break; @@ -50,8 +50,6 @@ unsafe fn second() -> ! { #[no_mangle] pub fn main() -> i32 { - // create semaphore & mutex - assert_eq!(semaphore_create(0) as usize, SEM_ID); // create threads let threads = vec![ thread_create(first as usize, 0), diff --git a/user/src/bin/mpsc_sem.rs b/user/src/bin/mpsc_sem.rs index 7b72bbb17..8b839bda9 100644 --- a/user/src/bin/mpsc_sem.rs +++ b/user/src/bin/mpsc_sem.rs @@ -9,12 +9,10 @@ extern crate alloc; use alloc::vec::Vec; use user_lib::exit; -use user_lib::{semaphore_create, semaphore_down, semaphore_up}; +use user_lib::Semaphore; use user_lib::{thread_create, waittid}; +use lazy_static::lazy_static; -const SEM_MUTEX: usize = 0; -const SEM_EMPTY: usize = 1; -const SEM_AVAIL: usize = 2; const BUFFER_SIZE: usize = 8; static mut BUFFER: [usize; BUFFER_SIZE] = [0; BUFFER_SIZE]; static mut FRONT: usize = 0; @@ -22,27 +20,33 @@ static mut TAIL: usize = 0; const PRODUCER_COUNT: usize = 4; const NUMBER_PER_PRODUCER: usize = 100; +lazy_static! { + static ref mutex: Semaphore = Semaphore::new(1); + static ref empty: Semaphore = Semaphore::new(BUFFER_SIZE as i32); + static ref avail: Semaphore = Semaphore::new(0); +} + unsafe fn producer(id: *const usize) -> ! { let id = *id; for _ in 0..NUMBER_PER_PRODUCER { - semaphore_down(SEM_EMPTY); - semaphore_down(SEM_MUTEX); + empty.wait(); + mutex.wait(); BUFFER[TAIL] = id; TAIL = (TAIL + 1) % BUFFER_SIZE; - semaphore_up(SEM_MUTEX); - semaphore_up(SEM_AVAIL); + mutex.post(); + avail.post(); } exit(0) } unsafe fn consumer() -> ! { for _ in 0..PRODUCER_COUNT * NUMBER_PER_PRODUCER { - semaphore_down(SEM_AVAIL); - semaphore_down(SEM_MUTEX); + avail.wait(); + mutex.wait(); print!("{} ", BUFFER[FRONT]); FRONT = (FRONT + 1) % BUFFER_SIZE; - semaphore_up(SEM_MUTEX); - semaphore_up(SEM_EMPTY); + mutex.post(); + empty.post(); } println!(""); exit(0) @@ -50,10 +54,6 @@ unsafe fn consumer() -> ! { #[no_mangle] pub fn main() -> i32 { - // create semaphores - assert_eq!(semaphore_create(1) as usize, SEM_MUTEX); - assert_eq!(semaphore_create(BUFFER_SIZE) as usize, SEM_EMPTY); - assert_eq!(semaphore_create(0) as usize, SEM_AVAIL); // create threads let ids: Vec<_> = (0..PRODUCER_COUNT).collect(); let mut threads = Vec::new(); diff --git a/user/src/bin/sync_sem.rs b/user/src/bin/sync_sem.rs index b8d1f79c2..15af35dee 100644 --- a/user/src/bin/sync_sem.rs +++ b/user/src/bin/sync_sem.rs @@ -8,29 +8,29 @@ extern crate alloc; use alloc::vec; use user_lib::exit; -use user_lib::{semaphore_create, semaphore_down, semaphore_up}; +use user_lib::Semaphore; use user_lib::{sleep, thread_create, waittid}; - -const SEM_SYNC: usize = 0; +use lazy_static::lazy_static; +lazy_static! { + static ref sem: Semaphore = Semaphore::new(0); +} unsafe fn first() -> ! { sleep(10); println!("First work and wakeup Second"); - semaphore_up(SEM_SYNC); + sem.post(); exit(0) } unsafe fn second() -> ! { println!("Second want to continue,but need to wait first"); - semaphore_down(SEM_SYNC); + sem.wait(); println!("Second can work now"); exit(0) } #[no_mangle] pub fn main() -> i32 { - // create semaphores - assert_eq!(semaphore_create(0) as usize, SEM_SYNC); // create threads let threads = vec![ thread_create(first as usize, 0), diff --git a/user/src/lib.rs b/user/src/lib.rs index d8a5a70b7..791163b20 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -176,16 +176,6 @@ pub fn futex_wake(flag_addr: *mut i32) -> isize { sys_futex_wake(flag_addr) } -pub fn semaphore_create(res_count: usize) -> isize { - sys_semaphore_create(res_count) -} -pub fn semaphore_up(sem_id: usize) { - sys_semaphore_up(sem_id); -} -pub fn semaphore_down(sem_id: usize) { - sys_semaphore_down(sem_id); -} - #[macro_export] macro_rules! vstore { ($var: expr, $value: expr) => { diff --git a/user/src/sync/mod.rs b/user/src/sync/mod.rs index e10a0794b..6f5415157 100644 --- a/user/src/sync/mod.rs +++ b/user/src/sync/mod.rs @@ -1,8 +1,10 @@ mod mutex; mod condvar; +mod semaphore; pub use mutex::*; pub use condvar::*; +pub use semaphore::*; #[inline(always)] pub fn load_reserved(addr: *const u32) -> u32 { diff --git a/user/src/sync/semaphore.rs b/user/src/sync/semaphore.rs new file mode 100644 index 000000000..dbb231590 --- /dev/null +++ b/user/src/sync/semaphore.rs @@ -0,0 +1,35 @@ +use super::*; +use core::cell::UnsafeCell; +use crate::syscall::{sys_futex_wait, sys_futex_wake}; + +pub struct Semaphore { + count: UnsafeCell, +} + +unsafe impl Send for Semaphore {} +unsafe impl Sync for Semaphore {} + +impl Semaphore { + pub fn new(count: i32) -> Self { + Self { + count: UnsafeCell::new(count) + } + } + + pub fn wait(&self) { + let addr = self.count.get(); + atomic_decrement(addr as *mut u32); + let val = unsafe { *addr }; + if val >= 0 { return; } + sys_futex_wait(addr, val); + } + + pub fn post(&self) { + let addr = self.count.get(); + atomic_increment(addr as *mut u32); + let val = unsafe { *addr }; + if val <= 0 { + sys_futex_wake(addr); + } + } +} \ No newline at end of file diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 04337d1d0..93efc5fc8 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -19,9 +19,6 @@ const SYSCALL_WAITPID: usize = 260; const SYSCALL_THREAD_CREATE: usize = 1000; const SYSCALL_GETTID: usize = 1001; const SYSCALL_WAITTID: usize = 1002; -const SYSCALL_SEMAPHORE_CREATE: usize = 1020; -const SYSCALL_SEMAPHORE_UP: usize = 1021; -const SYSCALL_SEMAPHORE_DOWN: usize = 1022; pub const FUTEX_WAIT: usize = 0; pub const FUTEX_WAKE: usize = 1; @@ -126,16 +123,4 @@ pub fn sys_futex_wait(flag_addr: *mut i32, expect: i32) -> isize { pub fn sys_futex_wake(flag_addr: *mut i32) -> isize { syscall(SYSCALL_FUTEX, [flag_addr as usize, FUTEX_WAKE, 0]) -} - -pub fn sys_semaphore_create(res_count: usize) -> isize { - syscall(SYSCALL_SEMAPHORE_CREATE, [res_count, 0, 0]) -} - -pub fn sys_semaphore_up(sem_id: usize) -> isize { - syscall(SYSCALL_SEMAPHORE_UP, [sem_id, 0, 0]) -} - -pub fn sys_semaphore_down(sem_id: usize) -> isize { - syscall(SYSCALL_SEMAPHORE_DOWN, [sem_id, 0, 0]) } \ No newline at end of file From ca3992e870c58bb2bd5b69e59b26eb62b2f47d30 Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sat, 19 Apr 2025 16:17:15 +0800 Subject: [PATCH 13/14] refactor(semaphore): reconstruct Semaphore based on Mutex and Condvar Now Semaphore is like to Zemaphore --- user/src/bin/adder_sem.rs | 68 ++++++++++++++++++++++++++++++++++++++ user/src/sync/semaphore.rs | 30 +++++++++-------- 2 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 user/src/bin/adder_sem.rs diff --git a/user/src/bin/adder_sem.rs b/user/src/bin/adder_sem.rs new file mode 100644 index 000000000..9631e61c1 --- /dev/null +++ b/user/src/bin/adder_sem.rs @@ -0,0 +1,68 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use alloc::vec::Vec; +use core::ptr::addr_of_mut; +use user_lib::{exit, get_time, thread_create, waittid}; +use user_lib::Semaphore; +use lazy_static::lazy_static; + +static mut A: usize = 0; +const PER_THREAD_DEFAULT: usize = 10000; +const THREAD_COUNT_DEFAULT: usize = 16; +static mut PER_THREAD: usize = 0; +lazy_static! { + static ref mutex: Semaphore = Semaphore::new(1); +} + +unsafe fn critical_section(t: &mut usize) { + let a = addr_of_mut!(A); + let cur = a.read_volatile(); + for _ in 0..500 { + *t = (*t) * (*t) % 10007; + } + a.write_volatile(cur + 1); +} +unsafe fn f(_id: usize) -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + // println!("Thread {} is getting lock...", id); + mutex.wait(); + // println!("Thread {} already get lock", id); + critical_section(&mut t); + mutex.post(); + // println!("Thread {} release lock", id); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let mut thread_count = THREAD_COUNT_DEFAULT; + let mut per_thread = PER_THREAD_DEFAULT; + if argc >= 2 { + thread_count = argv[1].parse().unwrap(); + if argc >= 3 { + per_thread = argv[2].parse().unwrap(); + } + } + unsafe { + PER_THREAD = per_thread; + } + + let start = get_time(); + let mut v = Vec::new(); + for id in 0..thread_count { + v.push(thread_create(f as usize, id) as usize); + } + for tid in v.into_iter() { + waittid(tid); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count); + 0 +} diff --git a/user/src/sync/semaphore.rs b/user/src/sync/semaphore.rs index dbb231590..ebf9a53e1 100644 --- a/user/src/sync/semaphore.rs +++ b/user/src/sync/semaphore.rs @@ -1,9 +1,10 @@ use super::*; use core::cell::UnsafeCell; -use crate::syscall::{sys_futex_wait, sys_futex_wake}; pub struct Semaphore { count: UnsafeCell, + cond: Condvar, + mutex: MutexSpin, } unsafe impl Send for Semaphore {} @@ -12,24 +13,27 @@ unsafe impl Sync for Semaphore {} impl Semaphore { pub fn new(count: i32) -> Self { Self { - count: UnsafeCell::new(count) + count: UnsafeCell::new(count), + cond: Condvar::new(), + mutex: MutexSpin::new(), } } pub fn wait(&self) { - let addr = self.count.get(); - atomic_decrement(addr as *mut u32); - let val = unsafe { *addr }; - if val >= 0 { return; } - sys_futex_wait(addr, val); + self.mutex.lock(); + let cnt_p = self.count.get(); + while unsafe { *cnt_p <= 0 } { + self.cond.wait(&self.mutex); + } + unsafe { *cnt_p -= 1; } + self.mutex.unlock(); } pub fn post(&self) { - let addr = self.count.get(); - atomic_increment(addr as *mut u32); - let val = unsafe { *addr }; - if val <= 0 { - sys_futex_wake(addr); - } + self.mutex.lock(); + let cnt_p = self.count.get(); + unsafe { *cnt_p += 1; } + self.cond.notify_one(); + self.mutex.unlock(); } } \ No newline at end of file From 2b0d75d8f7cf00e59f2115f9ab1cd2cb2aeb9ebf Mon Sep 17 00:00:00 2001 From: Tsihao Liao <143410405+FlowerPotOnRoof@users.noreply.github.com> Date: Sat, 19 Apr 2025 17:40:38 +0800 Subject: [PATCH 14/14] test(condsync_condvar.rs, condsync_sem.rs): small fix --- user/src/bin/condsync_condvar.rs | 4 ++-- user/src/bin/condsync_sem.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/user/src/bin/condsync_condvar.rs b/user/src/bin/condsync_condvar.rs index eb7d4891a..0b2b07981 100644 --- a/user/src/bin/condsync_condvar.rs +++ b/user/src/bin/condsync_condvar.rs @@ -35,10 +35,10 @@ unsafe fn second() -> ! { println!("Second want to continue,but need to wait A=1"); mutex.lock(); while A == 0 { - println!("Second: A is {}", &raw mut A as usize); + println!("Second: A is {}", A as usize); condvar.wait(&mutex); } - println!("A is {}, Second can work now", &raw mut A as usize); + println!("A is {}, Second can work now", A as usize); mutex.unlock(); exit(0) } diff --git a/user/src/bin/condsync_sem.rs b/user/src/bin/condsync_sem.rs index c6be357c6..ce23b92a6 100644 --- a/user/src/bin/condsync_sem.rs +++ b/user/src/bin/condsync_sem.rs @@ -36,7 +36,7 @@ unsafe fn second() -> ! { loop { mutex.lock(); if A == 0 { - println!("Second: A is {}", &raw mut A as usize); + println!("Second: A is {}", A as usize); mutex.unlock(); sem.wait(); } else { @@ -44,7 +44,7 @@ unsafe fn second() -> ! { break; } } - println!("A is {}, Second can work now", &raw mut A as usize); + println!("A is {}, Second can work now", A as usize); exit(0) }