Skip to main content

xwrust/xwos/lock/
mtx.rs

1//! XWOS RUST:互斥锁
2//! ========
3//!
4//! 互斥锁是用来保证不同线程正确访问共享数据的机制。访问共享数据的代码片段被称为临界区。
5//!
6//! 互斥锁 **只能** 用在 **线程上下文(Thread Context)** 。等待互斥锁的线程会被阻塞,并让出CPU的使用权。
7//!
8//! XWOS RUST框架的互斥锁是仿造 [`std::sync::Mutex`] 的来编写的。
9//!
10//! 互斥锁上锁后,可返回一个 **守卫** [`MutexGuard`] ,用于提供 **Scoped Lock** 机制:即只负责上锁,不用关心解锁。
11//! 解锁会由 [`MutexGuard`] 在其生命周期结束后自动触发。
12//!
13//! # 创建
14//!
15//! XWOS RUST的互斥锁可使用 [`Mutex::new()`] 创建。
16//!
17//! + 可以创建具有静态生命周期 [`static`] 约束的全局变量:
18//!
19//! ```rust
20//! use xwrust::xwos::lock::mtx::*;
21//!
22//! static GLOBAL_MUTEX: Mutex<u32> = Mutex::new(0);
23//! ```
24//!
25//! + 也可以使用 [`alloc::sync::Arc`] 在heap中创建:
26//!
27//!
28//! ```rust
29//! extern crate alloc;
30//! use alloc::sync::Arc;
31//!
32//! use xwrust::xwos::lock::mtx::*;
33//!
34//! pub fn xwrust_example_mutex() {
35//!     let mutex: Arc<Mutex<u32>> = Arc::new(Mutex::new(0));
36//! }
37//! ```
38//!
39//!
40//! # 初始化
41//!
42//! 无论以何种方式创建的互斥锁,都必须在使用前调用 [`Mutex::init()`] 进行初始化:
43//!
44//! ```rust
45//! pub fn xwrust_example_mutex() {
46//!     GLOBAL_MUTEX.init();
47//!     mutex.init();
48//! }
49//! ```
50//!
51//!
52//! # 解锁
53//!
54//! 上锁后返回的 [`MutexGuard`] 。 [`MutexGuard`] 的生命周期结束时,会自动解锁。
55//! 也可调用 [`Mutex::unlock()`] 主动消费掉 [`MutexGuard`] 来解锁。
56//!
57//!
58//! # 上锁
59//!
60//! ## 普通等待上锁
61//!
62//! [`Mutex::lock()`] 方法只可在 **线程** 上下文中使用:
63//!
64//! + 若线程无法获得锁,会阻塞等待。
65//! + 当锁的占用者解锁时,锁会唤醒优先级最高的线程,并让此线程获得锁。
66//! + 线程获得锁后返回 [`Ok()`] ,并在其中包含锁的守卫 [`MutexGuard`] 。
67//! + 当线程阻塞等待被中断时,会在 [`Err()`] 中返回 [`MutexError::Interrupt`] 。
68//!
69//! ## 超时等待上锁
70//!
71//! [`Mutex::lock_to()`] 方法只可在 **线程** 上下文中使用:
72//!
73//! + 若线程无法获得锁,会阻塞等待,等待时会指定一个唤醒时间点。
74//! + 当锁的占用者解锁时,锁会唤醒优先级最高的线程,并让此线程获得锁。
75//! + 线程获得锁后返回 [`Ok()`] ,并在其中包含锁的守卫 [`MutexGuard`] 。
76//! + 当线程阻塞等待被中断时,会在 [`Err()`] 中返回 [`MutexError::Interrupt`] 。
77//! + 当到达指定的唤醒时间点,线程被唤醒,并返回 [`MutexError::Timedout`] 。
78//!
79//! ## 不可中断等待上锁
80//!
81//! [`Mutex::lock_unintr()`] 方法只可在 **线程** 上下文中使用:
82//!
83//! + 若线程无法获得锁,会阻塞等待,且不可被中断,也不会超时。
84//! + 当锁的占用者解锁时,锁会唤醒优先级最高的线程,并让此线程获得锁。
85//! + 线程获得锁后返回 [`Ok()`] ,并在其中包含锁的守卫 [`MutexGuard`] 。
86//!
87//! ## 尝试等待上锁
88//!
89//! [`Mutex::trylock()`] 方法只可在 **线程** 上下文中使用,不会阻塞线程,只会检测锁是否可被获取:
90//!
91//! + 若线程可获得锁,立即获得锁并在 [`Ok()`] 中返回锁的守卫 [`MutexGuard`] 。
92//! + 若线程无法获得锁,立即在 [`Err()`] 中返回 [`MutexError::WouldBlock`] 。
93//!
94//!
95//! # 示例
96//!
97//! [XWOS/xwam/xwrust-example/xwrust_example_mutex](https://gitee.com/xwos/XWOS/blob/main/xwam/xwrust-example/xwrust_example_mutex/src/lib.rs)
98//!
99//!
100//! # 对比 [`std::sync::Mutex`]
101//!
102//! + XWOS RUST
103//!
104//! ```rust
105//! use xwrust::xwos::thd;
106//! use xwrust::xwos::lock::mtx::*;
107//! extern crate alloc;
108//! use alloc::sync::Arc;
109//!
110//! pub fn xwrust_example_mutex() {
111//!     // ...省略...
112//!     let lock: Arc<Mutex<u32>> = Arc::new(Mutex::new(0));
113//!     let lock_child = lock.clone();
114//!
115//!     match lock.lock() {
116//!         Ok(mut guard) => { // 主线程上锁成功
117//!             *guard = 1; // 访问共享变量
118//!         }
119//!         Err(e) => {
120//!             // 主线程上锁失败
121//!         }
122//!     }
123//!     // ...省略...
124//!     thd::Builder::new()
125//!         .name("child".into())
126//!         .spawn(move |_| {
127//!             // 子线程闭包
128//!             match lock_child.lock() {
129//!                 Ok(mut guard) => { // 子线程上锁成功
130//!                     *guard += 1;
131//!                 }
132//!                 Err(e) => { // 子线程上锁失败
133//!                 }
134//!             }
135//!         });
136//! }
137//! ```
138//!
139//! + [`std::sync::Mutex`]
140//!
141//! ```rust
142//! use std::sync::{Arc, Mutex};
143//! use std::thread;
144//!
145//! fn main() {
146//!     // 创建互斥锁的方法类似
147//!     let lock = Arc::new(Mutex::new(0_u32));
148//!     let lock2 = Arc::clone(&lock);
149//!
150//!     let _ = thread::spawn(move || -> () {
151//!         // 访问共享数据的方法类似:
152//!         // 子线程中对互斥锁上锁, unwrap() 从 Ok() 中取出 guard,再对 guard 解可变引用可得数据的可变引用
153//!         let guard = lock2.lock().unwrap();
154//!         *guard = 1;
155//!
156//!         // std库特有的机制:持有锁时 panic!() 将导致锁变成 **中毒状态(poisoned)** 。
157//!         panic!();
158//!     }).join();
159//!
160//!     // std库特有的机制:处理中毒状态的锁
161//!     let mut guard = match lock.lock() {
162//!         Ok(guard) => guard,
163//!         Err(poisoned) => poisoned.into_inner(),
164//!     };
165//!     *guard += 1;
166//! }
167//! ```
168//!
169//! ### 构建全局变量的方式
170//!
171//! + [`std::sync::Mutex`] 没有编译期构造函数,因此只能借助宏 [`lazy_static!`] 创建 [`static`] 约束的全局变量;
172//! + [`xwrust::xwos::lock::mtx`] 则可以直接在函数外部定义。
173//!
174//! ### 中毒锁机制
175//!
176//! + [`std::sync::Mutex`] 提供了 **Poisoned Mutex** 机制。
177//! 当通过 [`std::thread::spawn()`] 创建的子线程在持有 **互斥锁** 时,发生了 [`panic!()`] ,
178//! 此时 **互斥锁** 的状态被称为 **中毒(Poisoned)** 。 [`std::sync::Mutex`] 可在父线程中检测到此错误状态,并尝试恢复。
179//! + [`xwrust::xwos::lock::mtx`] 不提供此机制,用户必须处理 [`Ok()`] 与 [`Err()`] ,不可使用 [`unwrap()`]。
180//! 因为此机制需要依赖 **unwind** 机制 ,目前 **unwind** 在MCU上还不成熟:
181//!   + Gcc可以在MCU C++中使用 **try-catch**;
182//!   + LLVM(Clan++)还无法支持在MCU C++中使用 **try-catch**;
183//!   + Rust目前在MCU上还无法使用 **panic_unwind** 的 feature。
184//!
185//! [`std::sync::Mutex`]: <https://doc.rust-lang.org/std/sync/struct.Mutex.html>
186//! [`static`]: <https://doc.rust-lang.org/std/keyword.static.html>
187//! [`alloc::sync::Arc`]: <https://doc.rust-lang.org/alloc/sync/struct.Arc.html>
188//! [`lazy_static!`]: <https://lib.rs/crates/lazy_static>
189//! [`std::thread::spawn()`]: <https://doc.rust-lang.org/std/thread/fn.spawn.html>
190//! [`panic!()`]: <https://doc.rust-lang.org/core/macro.panic.html>
191//! [`Ok()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Ok>
192//! [`Err()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
193//! [`unwrap()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#method.unwrap>
194//! [`xwrust::xwos::lock::mtx`]: crate::xwos::lock::mtx
195
196extern crate core;
197use core::cell::UnsafeCell;
198use core::result::Result;
199use core::default::Default;
200use core::ops::Drop;
201use core::ops::Deref;
202use core::ops::DerefMut;
203use core::ptr;
204use core::mem;
205
206use crate::types::*;
207use crate::errno::*;
208use crate::xwos::sync::cond::*;
209
210
211extern "C" {
212    fn xwrustffi_mtx_init(mtx: *mut XwosMtx) -> XwEr;
213    fn xwrustffi_mtx_fini(mtx: *mut XwosMtx) -> XwEr;
214    fn xwrustffi_mtx_grab(mtx: *mut XwosMtx) -> XwEr;
215    fn xwrustffi_mtx_put(mtx: *mut XwosMtx) -> XwEr;
216    fn xwrustffi_mtx_get_tik(mtx: *mut XwosMtx) -> XwSq;
217    fn xwrustffi_mtx_acquire(mtx: *mut XwosMtx, tik: XwSq) -> XwEr;
218    fn xwrustffi_mtx_release(mtx: *mut XwosMtx, tik: XwSq) -> XwEr;
219    fn xwrustffi_mtx_unlock(mtx: *mut XwosMtx) -> XwEr;
220    fn xwrustffi_mtx_lock(mtx: *mut XwosMtx) -> XwEr;
221    fn xwrustffi_mtx_trylock(mtx: *mut XwosMtx) -> XwEr;
222    fn xwrustffi_mtx_lock_to(mtx: *mut XwosMtx, to: XwTm) -> XwEr;
223    fn xwrustffi_mtx_lock_unintr(mtx: *mut XwosMtx) -> XwEr;
224    fn xwrustffi_mtx_get_status(mtx: *mut XwosMtx, lkst: *mut XwSq) -> XwEr;
225}
226
227/// 互斥锁的错误码
228#[derive(Debug)]
229pub enum MutexError {
230    /// 互斥锁没有初始化
231    NotInit(XwEr),
232    /// 等待被中断
233    Interrupt(XwEr),
234    /// 尝试上锁失败
235    WouldBlock(XwEr),
236    /// 等待超时
237    Timedout(XwEr),
238    /// 不在线程上下文内
239    NotThreadContext(XwEr),
240    /// 抢占被关闭
241    DisPmpt(XwEr),
242    /// 中断底半部被关闭
243    DisBh(XwEr),
244    /// 中断被关闭
245    DisIrq(XwEr),
246    /// 未知错误
247    Unknown(XwEr),
248}
249
250impl MutexError {
251    /// 消费掉 `MutexError` 自身,返回内部的错误码。
252    pub fn unwrap(self) -> XwEr {
253        match self {
254            Self::NotInit(rc) => rc,
255            Self::Interrupt(rc) => rc,
256            Self::Timedout(rc) => rc,
257            Self::NotThreadContext(rc) => rc,
258            Self::DisPmpt(rc) => rc,
259            Self::DisBh(rc) => rc,
260            Self::DisIrq(rc) => rc,
261            Self::WouldBlock(rc) => rc,
262            Self::Unknown(rc) => rc,
263        }
264    }
265}
266
267/// XWOS互斥锁对象占用的内存大小
268#[cfg(target_pointer_width = "32")]
269pub const SIZEOF_XWOS_MTX: usize = 96;
270
271/// XWOS互斥锁对象占用的内存大小
272#[cfg(target_pointer_width = "64")]
273pub const SIZEOF_XWOS_MTX: usize = 192;
274
275/// 用于构建互斥锁的内存数组类型
276#[repr(C)]
277#[cfg_attr(target_pointer_width = "32", repr(align(8)))]
278#[cfg_attr(target_pointer_width = "64", repr(align(16)))]
279pub(crate) struct XwosMtx {
280    pub(crate) obj: [u8; SIZEOF_XWOS_MTX],
281}
282
283/// 用于构建互斥锁的内存数组常量
284///
285/// 此常量的作用是告诉编译器互斥锁对象需要多大的内存。
286pub(crate) const XWOS_MTX_INITIALIZER: XwosMtx = XwosMtx {
287    obj: [0; SIZEOF_XWOS_MTX],
288};
289
290/// 互斥锁对象结构体
291pub struct Mutex<T: ?Sized> {
292    /// 用于初始化XWOS互斥锁对象的内存空间
293    pub(crate) mtx: UnsafeCell<XwosMtx>,
294    /// 互斥锁对象的标签
295    pub(crate) tik: UnsafeCell<XwSq>,
296    /// 用户数据
297    pub(crate) data: UnsafeCell<T>,
298}
299
300impl<T> Mutex<T> {
301    /// 新建互斥锁对象
302    ///
303    /// 此方法是编译期方法,可用于新建 [`static`] 约束的全局变量。
304    ///
305    /// # 示例
306    ///
307    /// ```rust
308    /// use xwrust::xwos::lock::mtx::*;
309    ///
310    /// static GLOBAL_MUTEX: Mutex<u32> = Mutex::new(0);
311    /// ```
312    ///
313    /// [`static`]: https://doc.rust-lang.org/std/keyword.static.html
314    pub const fn new(t: T) -> Self {
315        Self {
316            mtx: UnsafeCell::new(XWOS_MTX_INITIALIZER),
317            tik: UnsafeCell::new(0),
318            data: UnsafeCell::new(t),
319        }
320    }
321}
322
323impl<T: ?Sized> Mutex<T> {
324    /// 初始化互斥锁对象
325    ///
326    /// 互斥锁对象必须调用此方法一次,方可正常使用。
327    ///
328    /// # 上下文
329    ///
330    /// + 任意
331    ///
332    /// # 示例
333    ///
334    /// ```rust
335    /// use xwrust::xwos::lock::mtx::*;
336    ///
337    /// static GLOBAL_MUTEX: Mutex<u32> = Mutex::new(0);
338    ///
339    /// pub fn xwrust_example_mutex() {
340    ///     // ...省略...
341    ///     GLOBAL_MUTEX.init();
342    ///     // 从此处开始 GLOBAL_MUTEX 可正常使用
343    /// }
344    /// ```
345    pub fn init(&self) {
346        unsafe {
347            let rc = xwrustffi_mtx_acquire(self.mtx.get(), *self.tik.get());
348            if rc == 0 {
349                xwrustffi_mtx_put(self.mtx.get());
350            } else {
351                xwrustffi_mtx_init(self.mtx.get());
352                *self.tik.get() = xwrustffi_mtx_get_tik(self.mtx.get());
353            }
354        }
355    }
356
357    /// 获取互斥锁,若线程无法获取互斥锁,就阻塞等待,直到能获得锁为止
358    ///
359    /// + 若成功获取互斥锁,将返回 **RAII Guard** : [`MutexGuard`] ,用于提供 **Scoped Lock** 机制。
360    ///   + [`MutexGuard`] 中包含 [`Mutex`] 的引用, 当 [`MutexGuard`] 生命周期结束时,会在 [`drop()`] 方法中自动解锁互斥锁。
361    /// + 若失败,将返回错误码 [`MutexError`] 。
362    ///
363    /// # 上下文
364    ///
365    /// + 线程
366    ///
367    /// # 错误码
368    ///
369    /// + [`MutexError::NotInit`] 互斥锁未被初始化
370    /// + [`MutexError::Interrupt`] 等待被中断
371    /// + [`MutexError::NotThreadContext`] 不在线程上下文中
372    /// + [`MutexError::DisPmpt`] 抢占被关闭
373    /// + [`MutexError::DisBh`] 中断底半部被关闭
374    /// + [`MutexError::DisIrq`] 中断被关闭
375    ///
376    /// # 示例
377    ///
378    /// ```rust
379    /// use xwrust::xwos::lock::mtx::*;
380    /// static GLOBAL_MUTEX: Mutex<u32> = Mutex::new(0);
381    ///
382    /// pub fn xwrust_example_mutex() {
383    ///     // ...省略...
384    ///     GLOBAL_MUTEX.init();
385    ///     match GLOBAL_MUTEX.lock() {
386    ///         Ok(mut guard) => { // 上锁成功
387    ///             *guard = 1; // 访问共享变量
388    ///         } // guard 生命周期结束,自动解锁
389    ///         Err(e) => {
390    ///             // 上锁失败
391    ///         }
392    ///     }
393    /// }
394    /// ```
395    ///
396    /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
397    pub fn lock(&self) -> Result<MutexGuard<'_, T>, MutexError> {
398        unsafe {
399            let mut rc = xwrustffi_mtx_acquire(self.mtx.get(), *self.tik.get());
400            if rc == 0 {
401                rc = xwrustffi_mtx_lock(self.mtx.get());
402                xwrustffi_mtx_put(self.mtx.get());
403                if 0 == rc {
404                    Ok(MutexGuard::new(self))
405                } else if -EINTR == rc {
406                    Err(MutexError::Interrupt(rc))
407                } else if -ENOTTHDCTX == rc {
408                    Err(MutexError::NotThreadContext(rc))
409                } else if -EDISPMPT == rc {
410                    Err(MutexError::DisPmpt(rc))
411                } else if -EDISBH == rc {
412                    Err(MutexError::DisBh(rc))
413                } else if -EDISIRQ == rc {
414                    Err(MutexError::DisIrq(rc))
415                } else {
416                    Err(MutexError::Unknown(rc))
417                }
418            } else {
419                Err(MutexError::NotInit(rc))
420            }
421        }
422    }
423
424    /// 尝试获取互斥锁,若线程无法获取互斥锁,立即返回错误
425    ///
426    /// + 若成功获取互斥锁,将返回 **RAII Guard** : [`MutexGuard`] ,用于提供 **Scoped Lock** 机制。
427    ///   + [`MutexGuard`] 中包含 [`Mutex`] 的引用, 当 [`MutexGuard`] 生命周期结束时,会在 [`drop()`] 方法中自动解锁互斥锁。
428    /// + 若失败,将返回错误码 [`MutexError`] 。
429    ///
430    /// # 上下文
431    ///
432    /// + 线程
433    ///
434    /// # 错误码
435    ///
436    /// + [`MutexError::NotInit`] 互斥锁未被初始化
437    /// + [`MutexError::WouldBlock`] 尝试获取锁失败
438    /// + [`MutexError::NotThreadContext`] 不在线程上下文中
439    ///
440    /// # 示例
441    /// ```rust
442    /// use xwrust::xwos::lock::mtx::*;
443    /// static GLOBAL_MUTEX: Mutex<u32> = Mutex::new(0);
444    ///
445    /// pub fn xwrust_example_mutex() {
446    ///     // ...省略...
447    ///     GLOBAL_MUTEX.init();
448    ///     match GLOBAL_MUTEX.trylock() {
449    ///         Ok(mut guard) => { // 上锁成功
450    ///             *guard = 1; // 访问共享变量
451    ///         } // guard 生命周期结束,自动解锁
452    ///         Err(e) => {
453    ///             // 上锁失败
454    ///         }
455    ///     }
456    /// }
457    /// ```
458    ///
459    /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
460    pub fn trylock(&self) -> Result<MutexGuard<'_, T>, MutexError> {
461        unsafe {
462            let mut rc = xwrustffi_mtx_acquire(self.mtx.get(), *self.tik.get());
463            if rc == 0 {
464                rc = xwrustffi_mtx_trylock(self.mtx.get());
465                xwrustffi_mtx_put(self.mtx.get());
466                if 0 == rc {
467                    Ok(MutexGuard::new(self))
468                } else if -EWOULDBLOCK == rc {
469                    Err(MutexError::WouldBlock(rc))
470                } else if -ENOTTHDCTX == rc {
471                    Err(MutexError::NotThreadContext(rc))
472                } else {
473                    Err(MutexError::Unknown(rc))
474                }
475            } else {
476                Err(MutexError::NotInit(rc))
477            }
478        }
479    }
480
481    /// 获取互斥锁,若线程无法获取互斥锁,就限时阻塞等待
482    ///
483    /// + 若成功获取互斥锁,将返回 **RAII Guard** : [`MutexGuard`] ,用于提供 **Scoped Lock** 机制。
484    ///   + [`MutexGuard`] 中包含 [`Mutex`] 的引用, 当 [`MutexGuard`] 生命周期结束时,会在 [`drop()`] 方法中自动解锁互斥锁。
485    /// + 若失败,将返回错误码 [`MutexError`] 。
486    ///
487    /// # 参数说明
488    ///
489    /// + to: 期望唤醒的时间点
490    ///
491    /// # 上下文
492    ///
493    /// + 线程
494    ///
495    /// # 错误码
496    ///
497    /// + [`MutexError::NotInit`] 互斥锁未被初始化
498    /// + [`MutexError::Interrupt`] 等待被中断
499    /// + [`MutexError::Timedout`] 等待超时
500    /// + [`MutexError::NotThreadContext`] 不在线程上下文中
501    /// + [`MutexError::DisPmpt`] 抢占被关闭
502    /// + [`MutexError::DisBh`] 中断底半部被关闭
503    /// + [`MutexError::DisIrq`] 中断被关闭
504    ///
505    /// # 示例
506    ///
507    /// ```rust
508    /// use xwrust::xwtm;
509    /// use xwrust::xwos::lock::mtx::*;
510    /// static GLOBAL_MUTEX: Mutex<u32> = Mutex::new(0);
511    ///
512    /// pub fn xwrust_example_mutex() {
513    ///     // ...省略...
514    ///     GLOBAL_MUTEX.init();
515    ///     match GLOBAL_MUTEX.lock_to(xwtm::ft(xwtm::s(10))) { // 最多等待10s
516    ///         Ok(mut guard) => { // 上锁成功
517    ///             *guard = 1; // 访问共享变量
518    ///         } // guard 生命周期结束,自动解锁
519    ///         Err(e) => {
520    ///             // 上锁失败
521    ///         }
522    ///     }
523    /// }
524    /// ```
525    ///
526    /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
527    pub fn lock_to(&self, to: XwTm) -> Result<MutexGuard<'_, T>, MutexError> {
528        unsafe {
529            let mut rc = xwrustffi_mtx_acquire(self.mtx.get(), *self.tik.get());
530            if rc == 0 {
531                rc = xwrustffi_mtx_lock_to(self.mtx.get(), to);
532                xwrustffi_mtx_put(self.mtx.get());
533                if 0 == rc {
534                    Ok(MutexGuard::new(self))
535                } else if -EINTR == rc {
536                    Err(MutexError::Interrupt(rc))
537                } else if -ETIMEDOUT == rc {
538                    Err(MutexError::Timedout(rc))
539                } else if -ENOTTHDCTX == rc {
540                    Err(MutexError::NotThreadContext(rc))
541                } else if -EDISPMPT == rc {
542                    Err(MutexError::DisPmpt(rc))
543                } else if -EDISBH == rc {
544                    Err(MutexError::DisBh(rc))
545                } else if -EDISIRQ == rc {
546                    Err(MutexError::DisIrq(rc))
547                } else {
548                    Err(MutexError::Unknown(rc))
549                }
550            } else {
551                Err(MutexError::NotInit(rc))
552            }
553        }
554    }
555
556    /// 获取互斥锁,若线程无法获取互斥锁,就阻塞等待,且不可中断,直到能获得锁为止
557    ///
558    /// + 若成功获取互斥锁,将返回 **RAII Guard** : [`MutexGuard`] ,用于提供 **Scoped Lock** 机制。
559    ///   + [`MutexGuard`] 中包含 [`Mutex`] 的引用, 当 [`MutexGuard`] 生命周期结束时,会在 [`drop()`] 方法中自动解锁互斥锁。
560    /// + 若失败,将返回错误码 [`MutexError`] 。
561    ///
562    /// # 上下文
563    ///
564    /// + 线程
565    ///
566    /// # 错误码
567    ///
568    /// + [`MutexError::NotInit`] 互斥锁未被初始化
569    /// + [`MutexError::NotThreadContext`] 不在线程上下文中
570    /// + [`MutexError::DisPmpt`] 抢占被关闭
571    /// + [`MutexError::DisBh`] 中断底半部被关闭
572    /// + [`MutexError::DisIrq`] 中断被关闭
573    ///
574    /// # 示例
575    ///
576    /// ```rust
577    /// use xwrust::xwos::lock::mtx::*;
578    /// static GLOBAL_MUTEX: Mutex<u32> = Mutex::new(0);
579    ///
580    /// pub fn xwrust_example_mutex() {
581    ///     // ...省略...
582    ///     GLOBAL_MUTEX.init();
583    ///     match GLOBAL_MUTEX.lock_unintr() {
584    ///         Ok(mut guard) => { // 上锁成功
585    ///             *guard = 1; // 访问共享变量
586    ///         } // guard 生命周期结束,自动解锁
587    ///         Err(e) => {
588    ///             // 上锁失败
589    ///         }
590    ///     }
591    /// }
592    /// ```
593    ///
594    /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
595    pub fn lock_unintr(&self) -> Result<MutexGuard<'_, T>, MutexError> {
596        unsafe {
597            let mut rc = xwrustffi_mtx_acquire(self.mtx.get(), *self.tik.get());
598            if rc == 0 {
599                rc = xwrustffi_mtx_lock_unintr(self.mtx.get());
600                xwrustffi_mtx_put(self.mtx.get());
601                if 0 == rc {
602                    Ok(MutexGuard::new(self))
603                } else if -EWOULDBLOCK == rc {
604                    Err(MutexError::WouldBlock(rc))
605                } else if -ENOTTHDCTX == rc {
606                    Err(MutexError::NotThreadContext(rc))
607                } else if -EDISPMPT == rc {
608                    Err(MutexError::DisPmpt(rc))
609                } else if -EDISBH == rc {
610                    Err(MutexError::DisBh(rc))
611                } else if -EDISIRQ == rc {
612                    Err(MutexError::DisIrq(rc))
613                } else {
614                    Err(MutexError::Unknown(rc))
615                }
616            } else {
617                Err(MutexError::NotInit(rc))
618            }
619        }
620    }
621
622    /// 释放 [`MutexGuard`],并在 [`drop()`] 方法中解锁互斥锁
623    ///
624    /// # 上下文
625    ///
626    /// + 线程
627    ///
628    /// # 示例
629    ///
630    /// ```rust
631    /// use xwrust::xwos::lock::mtx::*;
632    /// static GLOBAL_MUTEX: Mutex<u32> = Mutex::new(0);
633    ///
634    /// pub fn xwrust_example_mutex() {
635    ///     // ...省略...
636    ///     GLOBAL_MUTEX.init();
637    ///     match GLOBAL_MUTEX.lock() {
638    ///         Ok(mut guard) => { // 上锁成功
639    ///             *guard = 1; // 访问共享变量
640    ///             Mutex::unlock(guard); // 主动解锁
641    ///         }
642    ///         Err(e) => {
643    ///             // 上锁失败
644    ///         }
645    ///     }
646    /// }
647    /// ```
648    ///
649    /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
650    pub fn unlock(guard: MutexGuard<'_, T>) {
651        drop(guard)
652    }
653}
654
655unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
656unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
657
658impl<T> From<T> for Mutex<T> {
659    /// 从数据新建互斥锁对象
660    ///
661    /// 此方法会将数据所有权转移到互斥锁对象的内部
662    ///
663    /// 等价于 [`Mutex::new`]
664    fn from(t: T) -> Self {
665        Mutex::new(t)
666    }
667}
668
669impl<T: ?Sized + Default> Default for Mutex<T> {
670    fn default() -> Mutex<T> {
671        Mutex::new(Default::default())
672    }
673}
674
675impl<T: ?Sized> Drop for Mutex<T> {
676    fn drop(&mut self) {
677        unsafe {
678            xwrustffi_mtx_fini(self.mtx.get());
679        }
680    }
681}
682
683/// 互斥锁对象的RAII Guard
684///
685/// **RAII Guard** 用于提供 **Scoped Lock** 机制。
686///
687/// + [`MutexGuard`] 中包含 [`Mutex`] 的引用, 当 [`MutexGuard`] 生命周期结束时,会在 [`drop()`] 方法中自动解锁互斥锁。
688/// + [`MutexGuard`] 不可在线程之间转移所有权,因为其 [`drop()`] 方法包含解锁的语义,上锁和解锁必须在同一线程;
689/// + [`MutexGuard`] 虽然可以在多线程中传递引用( [`Sync`] 约束),但其实现中没有 **unlock()** 方法,意味着其他线程即便拿到引用也不能解锁。
690///
691/// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
692/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Send.html
693pub struct MutexGuard<'a, T: ?Sized + 'a> {
694    /// 互斥锁的引用
695    lock: &'a Mutex<T>,
696}
697
698impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
699unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
700
701impl<'a, T: ?Sized> MutexGuard<'a, T> {
702    fn new(lock: &'a Mutex<T>) -> MutexGuard<'a, T> {
703        MutexGuard { lock: lock }
704    }
705
706    /// 阻塞当前线程,直到被条件量唤醒
707    ///
708    /// 此方法会消费互斥锁的守卫(Guard),并当线程阻塞时,在条件量内部释放互斥锁。
709    /// 当条件成立,线程被唤醒,会在条件量内部上锁互斥锁,并重新返回互斥锁的守卫(Guard)。
710    ///
711    /// + 当返回互斥锁的守卫 [`MutexGuard`] 时,互斥锁已经被重新上锁;
712    /// + 当返回 [`Err()`] 时,互斥锁未被上锁。
713    ///
714    /// # 参数说明
715    ///
716    /// + cond: 条件量的引用
717    ///
718    /// # 上下文
719    ///
720    /// + 线程
721    ///
722    /// # 错误码
723    ///
724    /// + [`CondError::NotInit`] 条件量未被初始化
725    /// + [`CondError::Interrupt`] 等待被中断
726    /// + [`CondError::NotThreadContext`] 不在线程上下文中
727    ///
728    /// # 示例
729    ///
730    /// ```rust
731    /// use xwrust::xwos::thd;
732    /// use xwrust::xwos::lock::mtx::*;
733    /// use xwrust::xwos::sync::cond::*;
734    /// extern crate alloc;
735    /// use alloc::sync::Arc;
736    ///
737    /// pub fn xwrust_example_mutex() {
738    ///     let pair = Arc::new((Mutex::new(true), Cond::new()));
739    ///     pair.0.init();
740    ///     pair.1.init();
741    ///     let pair_c = pair.clone();
742    ///
743    ///     thd::Builder::new()
744    ///         .name("child".into())
745    ///         .spawn(move |_| { // 子线程闭包
746    ///             cthd::sleep(xwtm::ms(500));
747    ///             let (lock, cvar) = &*pair_c;
748    ///             match lock_child.lock() {
749    ///                 Ok(mut guard) => {
750    ///                     *guard = false; // 设置共享数据
751    ///                     drop(guard); // 先解锁再触发条件可提高效率
752    ///                     cvar.broadcast();
753    ///                 },
754    ///                 Err(e) => { // 子线程上锁失败
755    ///                 },
756    ///             }
757    ///         });
758    ///     let (lock, cvar) = &*pair;
759    ///     let mut guard;
760    ///     match lock.lock() {
761    ///         Ok(g) => {
762    ///             guard = g;
763    ///             while *guard {
764    ///                 match guard.wait(cvar) {
765    ///                     Ok(g) => { // 唤醒
766    ///                         guard = g;
767    ///                     },
768    ///                     Err(e) => { // 等待条件量失败
769    ///                         break;
770    ///                     },
771    ///                 }
772    ///             }
773    ///         },
774    ///         Err(e) => { // 上锁失败
775    ///         },
776    ///     }
777    /// }
778    /// ```
779    ///
780    /// [`Err()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
781    pub fn wait(self, cond: &Cond) -> Result<MutexGuard<'a, T>, CondError> {
782        unsafe {
783            let mut rc = xwrustffi_cond_acquire(cond.cond.get(), *cond.tik.get());
784            if rc == 0 {
785                let mut lkst = 0;
786                rc = xwrustffi_cond_wait(cond.cond.get(),
787                                         self.lock.mtx.get() as _, XWOS_LK_MTX, ptr::null_mut(),
788                                         &mut lkst);
789                xwrustffi_cond_put(cond.cond.get());
790                if 0 == rc {
791                    Ok(self)
792                } else {
793                    if XWOS_LKST_LOCKED == lkst {
794                        drop(self);
795                    } else {
796                        mem::forget(self);
797                    }
798                    if -EINTR == rc {
799                        Err(CondError::Interrupt(rc))
800                    } else if -ENOTTHDCTX == rc {
801                        Err(CondError::NotThreadContext(rc))
802                    } else {
803                        Err(CondError::Unknown(rc))
804                    }
805                }
806            } else {
807                drop(self);
808                Err(CondError::NotInit(rc))
809            }
810        }
811    }
812
813    /// 限时阻塞当前线程,直到被条件量唤醒
814    ///
815    /// 此方法会消费互斥锁的守卫(Guard),并当线程阻塞时,在条件量内部释放互斥锁。
816    /// 当条件成立,线程被唤醒,会在条件量内部上锁互斥锁,并重新返回互斥锁的守卫(Guard)。
817    /// 当超时后,将返回错误。
818    ///
819    /// + 当返回互斥锁的守卫 [`MutexGuard`] 时,互斥锁已经被重新上锁;
820    /// + 当返回 [`Err()`] 时,互斥锁未被上锁。
821    ///
822    /// # 参数说明
823    ///
824    /// + cond: 条件量的引用
825    /// + to: 期望唤醒的时间点
826    ///
827    /// # 上下文
828    ///
829    /// + 线程
830    ///
831    /// # 错误码
832    ///
833    /// + [`CondError::NotInit`] 条件量未被初始化
834    /// + [`CondError::Interrupt`] 等待被中断
835    /// + [`CondError::Timedout`] 等待超时
836    /// + [`CondError::NotThreadContext`] 不在线程上下文中
837    ///
838    /// # 示例
839    ///
840    /// ```rust
841    /// use xwrust::xwos::thd;
842    /// use xwrust::xwos::lock::mtx::*;
843    /// use xwrust::xwos::sync::cond::*;
844    /// extern crate alloc;
845    /// use alloc::sync::Arc;
846    ///
847    /// pub fn xwrust_example_mutex() {
848    ///     let pair = Arc::new((Mutex::new(true), Cond::new()));
849    ///     pair.0.init();
850    ///     pair.1.init();
851    ///     let pair_c = pair.clone();
852    ///
853    ///     thd::Builder::new()
854    ///         .name("child".into())
855    ///         .spawn(move |_| { // 子线程闭包
856    ///             cthd::sleep(xwtm::ms(500));
857    ///             let (lock, cvar) = &*pair_c;
858    ///             match lock_child.lock() {
859    ///                 Ok(mut guard) => {
860    ///                     *guard = false; // 设置共享数据
861    ///                     drop(guard); // 先解锁再触发条件可提高效率
862    ///                     cvar.broadcast();
863    ///                 },
864    ///                 Err(e) => { // 子线程上锁失败
865    ///                 },
866    ///             }
867    ///         });
868    ///     let (lock, cvar) = &*pair;
869    ///     let mut guard;
870    ///     match lock.lock() {
871    ///         Ok(g) => {
872    ///             guard = g;
873    ///             while *guard {
874    ///                 match guard.wait_to(cvar, xwtm::ft(xwtm::s(2))) {
875    ///                     Ok(g) => { // 唤醒
876    ///                         guard = g;
877    ///                     },
878    ///                     Err(e) => { // 等待条件量失败
879    ///                         break;
880    ///                     },
881    ///                 }
882    ///             }
883    ///         },
884    ///         Err(e) => { // 上锁失败
885    ///         },
886    ///     }
887    /// }
888    /// ```
889    ///
890    /// [`Err()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
891    pub fn wait_to(self, cond: &Cond, to: XwTm) -> Result<MutexGuard<'a, T>, CondError> {
892        unsafe {
893            let mut rc = xwrustffi_cond_acquire(cond.cond.get(), *cond.tik.get());
894            if rc == 0 {
895                let mut lkst = 0;
896                rc = xwrustffi_cond_wait_to(cond.cond.get(),
897                                            self.lock.mtx.get() as _, XWOS_LK_MTX, ptr::null_mut(),
898                                            to, &mut lkst);
899                xwrustffi_cond_put(cond.cond.get());
900                if 0 == rc {
901                    Ok(self)
902                } else {
903                    if XWOS_LKST_LOCKED == lkst {
904                        drop(self);
905                    } else {
906                        mem::forget(self);
907                    }
908                    if -EINTR == rc {
909                        Err(CondError::Interrupt(rc))
910                    } else if -ETIMEDOUT == rc {
911                        Err(CondError::Timedout(rc))
912                    } else if -ENOTTHDCTX == rc {
913                        Err(CondError::NotThreadContext(rc))
914                    } else {
915                        Err(CondError::Unknown(rc))
916                    }
917                }
918            } else {
919                drop(self);
920                Err(CondError::NotInit(rc))
921            }
922        }
923    }
924
925    /// 阻塞当前线程,直到被条件量唤醒,且阻塞不可被中断
926    ///
927    /// 此方法会消费互斥锁的守卫(Guard),并当线程阻塞时,在条件量内部释放互斥锁。
928    /// 当条件成立,线程被唤醒,会在条件量内部上锁互斥锁,并重新返回互斥锁的守卫(Guard)。
929    ///
930    /// + 当返回互斥锁的守卫 [`MutexGuard`] 时,互斥锁已经被重新上锁;
931    /// + 当返回 [`Err()`] 时,互斥锁未被上锁。
932    ///
933    /// # 参数说明
934    ///
935    /// + cond: 条件量的引用
936    ///
937    /// # 上下文
938    ///
939    /// + 线程
940    ///
941    /// # 错误码
942    ///
943    /// + [`CondError::NotInit`] 条件量未被初始化
944    /// + [`CondError::NotThreadContext`] 不在线程上下文中
945    ///
946    /// # 示例
947    ///
948    /// ```rust
949    /// use xwrust::xwos::thd;
950    /// use xwrust::xwos::lock::mtx::*;
951    /// use xwrust::xwos::sync::cond::*;
952    /// extern crate alloc;
953    /// use alloc::sync::Arc;
954    ///
955    /// pub fn xwrust_example_mutex() {
956    ///     let pair = Arc::new((Mutex::new(true), Cond::new()));
957    ///     pair.0.init();
958    ///     pair.1.init();
959    ///     let pair_c = pair.clone();
960    ///
961    ///     thd::Builder::new()
962    ///         .name("child".into())
963    ///         .spawn(move |_| { // 子线程闭包
964    ///             cthd::sleep(xwtm::ms(500));
965    ///             let (lock, cvar) = &*pair_c;
966    ///             match lock_child.lock() {
967    ///                 Ok(mut guard) => {
968    ///                     *guard = false; // 设置共享数据
969    ///                     drop(guard); // 先解锁再触发条件可提高效率
970    ///                     cvar.broadcast();
971    ///                 },
972    ///                 Err(e) => { // 子线程上锁失败
973    ///                 },
974    ///             }
975    ///         });
976    ///     let (lock, cvar) = &*pair;
977    ///     let mut guard;
978    ///     match lock.lock() {
979    ///         Ok(g) => {
980    ///             guard = g;
981    ///             while *guard {
982    ///                 match guard.wait_unintr(cvar) {
983    ///                     Ok(g) => { // 唤醒
984    ///                         guard = g;
985    ///                     },
986    ///                     Err(e) => { // 等待条件量失败
987    ///                         break;
988    ///                     },
989    ///                 }
990    ///             }
991    ///         },
992    ///         Err(e) => { // 上锁失败
993    ///         },
994    ///     }
995    /// }
996    /// ```
997    ///
998    /// [`Err()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
999    pub fn wait_unintr(self, cond: &Cond) -> Result<MutexGuard<'a, T>, CondError> {
1000        unsafe {
1001            let mut rc = xwrustffi_cond_acquire(cond.cond.get(), *cond.tik.get());
1002            if rc == 0 {
1003                let mut lkst = 0;
1004                rc = xwrustffi_cond_wait_unintr(cond.cond.get(),
1005                                                self.lock.mtx.get() as _, XWOS_LK_MTX, ptr::null_mut(),
1006                                                &mut lkst);
1007                xwrustffi_cond_put(cond.cond.get());
1008                if 0 == rc {
1009                    Ok(self)
1010                } else {
1011                    if XWOS_LKST_LOCKED == lkst {
1012                        drop(self);
1013                    } else {
1014                        mem::forget(self);
1015                    }
1016                    if -ENOTTHDCTX == rc {
1017                        Err(CondError::NotThreadContext(rc))
1018                    } else {
1019                        Err(CondError::Unknown(rc))
1020                    }
1021                }
1022            } else {
1023                drop(self);
1024                Err(CondError::NotInit(rc))
1025            }
1026        }
1027    }
1028}
1029
1030impl<T: ?Sized> Deref for MutexGuard<'_, T> {
1031    type Target = T;
1032
1033    fn deref(&self) -> &T {
1034        unsafe { &*self.lock.data.get() }
1035    }
1036}
1037
1038impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
1039    fn deref_mut(&mut self) -> &mut T {
1040        unsafe { &mut *self.lock.data.get() }
1041    }
1042}
1043
1044impl<T: ?Sized> Drop for MutexGuard<'_, T> {
1045    #[inline]
1046    fn drop(&mut self) {
1047        unsafe {
1048            xwrustffi_mtx_unlock(self.lock.mtx.get());
1049        }
1050    }
1051}