xref: /drstd/src/std/sys/itron/mutex.rs (revision 86982c5e9b2eaa583327251616ee822c36288824)
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