1 //! Mutex implementation backed by μITRON mutexes. Assumes `acre_mtx` and 2 //! `TA_INHERIT` are available. 3 use super::{ 4 abi, 5 error::{expect_success, expect_success_aborting, fail, ItronError}, 6 spin::SpinIdOnceCell, 7 }; 8 9 pub struct Mutex { 10 /// The ID of the underlying mutex object 11 mtx: SpinIdOnceCell<()>, 12 } 13 14 /// Create a mutex object. This function never panics. 15 fn new_mtx() -> Result<abi::ID, ItronError> { 16 ItronError::err_if_negative(unsafe { 17 abi::acre_mtx(&abi::T_CMTX { 18 // Priority inheritance mutex 19 mtxatr: abi::TA_INHERIT, 20 // Unused 21 ceilpri: 0, 22 }) 23 }) 24 } 25 26 impl Mutex { 27 #[inline] 28 pub const fn new() -> Mutex { 29 Mutex { 30 mtx: SpinIdOnceCell::new(), 31 } 32 } 33 34 /// Get the inner mutex's ID, which is lazily created. 35 fn raw(&self) -> abi::ID { 36 match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) { 37 Ok((id, ())) => id, 38 Err(e) => fail(e, &"acre_mtx"), 39 } 40 } 41 42 pub fn lock(&self) { 43 let mtx = self.raw(); 44 expect_success(unsafe { abi::loc_mtx(mtx) }, &"loc_mtx"); 45 } 46 47 pub unsafe fn unlock(&self) { 48 let mtx = unsafe { self.mtx.get_unchecked().0 }; 49 expect_success_aborting(unsafe { abi::unl_mtx(mtx) }, &"unl_mtx"); 50 } 51 52 pub fn try_lock(&self) -> bool { 53 let mtx = self.raw(); 54 match unsafe { abi::ploc_mtx(mtx) } { 55 abi::E_TMOUT => false, 56 er => { 57 expect_success(er, &"ploc_mtx"); 58 true 59 } 60 } 61 } 62 } 63 64 impl Drop for Mutex { 65 fn drop(&mut self) { 66 if let Some(mtx) = self.mtx.get().map(|x| x.0) { 67 expect_success_aborting(unsafe { abi::del_mtx(mtx) }, &"del_mtx"); 68 } 69 } 70 } 71 72 pub(super) struct MutexGuard<'a>(&'a Mutex); 73 74 impl<'a> MutexGuard<'a> { 75 #[inline] 76 pub(super) fn lock(x: &'a Mutex) -> Self { 77 x.lock(); 78 Self(x) 79 } 80 } 81 82 impl Drop for MutexGuard<'_> { 83 #[inline] 84 fn drop(&mut self) { 85 unsafe { self.0.unlock() }; 86 } 87 } 88