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}