Skip to main content

xwrust/xwos/sync/
cond.rs

1//! XWOS RUST:条件量
2//! ========
3//!
4//! 条件量是操作系统比较底层的同步机制,可以同时阻塞多个线程。当条件成立,条件量可以唤醒一个或所有正在等待的线程。
5//!
6//! XWOS RUST的条件量通常还需要一个伴生的锁一起工作。线程通常需要持有 **锁** 的情况下去等待条件量,
7//! 条件量阻塞线程的同时会同步释放 **锁** 。当条件成立,线程被唤醒时,条件量会自动获得 **锁**。
8//!
9//! XWOS RUST的条件量机制,主要包括以下操作:
10//!
11//! + 线程A等待条件量的 **条件** 成立而阻塞;
12//! + 另一个线程B或中断或其他任意上下文使 **条件** 成立,并唤醒条件量上阻塞的线程,可以 **单播** 也可以 **广播** 。
13//!   为了防止两个上下文竞争 **条件** ,条件量需要和一个 **锁** 一起使用,锁用于保护 **条件** 不会被同时访问。
14//! + XWOS的条件量的锁的类型包括:
15//!   + 互斥锁
16//!   + 自旋锁
17//!   + 顺序锁的独占读锁
18//!   + 顺序锁的写锁
19//!
20//!
21//! # 创建
22//!
23//! XWOS RUST的条件量可使用 [`Cond::new()`] 创建。
24//!
25//! + 可以创建具有静态生命周期 [`static`] 约束的全局变量:
26//!
27//! ```rust
28//! use xwrust::xwos::sync::cond::*;
29//!
30//! static GLOBAL_COND: Cond = Cond::new();
31//! ```
32//!
33//! + 也可以使用 [`alloc::sync::Arc`] 在heap中创建:
34//!
35//! ```rust
36//! extern crate alloc;
37//! use alloc::sync::Arc;
38//!
39//! use xwrust::xwos::sync::cond::*;
40//!
41//! pub fn xwrust_example_cond() {
42//!     let cond = Arc::new(Cond::new());
43//!     let cond_c = cond.clone();
44//! }
45//! ```
46//!
47//!
48//! # 初始化
49//!
50//! 无论以何种方式创建的条件量,都必须在使用前调用 [`Cond::init()`] 进行初始化:
51//!
52//! ```rust
53//! pub fn xwrust_example_cond() {
54//!     GLOBAL_COND.init();
55//!     cond.init();
56//! }
57//! ```
58//!
59//!
60//! # 单播
61//!
62//! [`Cond::unicast()`] 方法可用来使得条件量的条件成立,但只唤醒一个线程。此方法可在 **任意** 上下文使用。
63//!
64//!
65//! # 广播
66//!
67//! [`Cond::broadcast()`] 方法可用来使得条件量的条件成立,并唤醒全部线程。此方法可在 **任意** 上下文使用。
68//!
69//!
70//! # 冻结与解冻
71//!
72//! ## 冻结
73//!
74//! XWOS RUST的条件量可以使用方法 [`Cond::freeze()`] 进行 **冻结** 操作,被冻结的条件量不能再进行 **单薄** 和 **广播** 操作。
75//!
76//! ## 解冻
77//!
78//! [`Cond::thaw()`] 方法是**冻结** 操作的逆操作。条件量解冻后,可重新进行 **单薄** 和 **广播** 操作。
79//!
80//!
81//! # 等待
82//!
83//! 等待操作需要在获得锁的情况下进行,因此 **等待** 的方法实现在锁的 **守卫(Guard)** 内部,以便区分锁的类型:
84//!
85//! ## 普通等待
86//!
87//! **普通等待** 的方法只可在 **线程** 上下文中使用,会 **消费** 锁的 **守卫(Guard)** ,然后线程阻塞等待条件量:
88//!
89//! + 通过 **单播** 或 **广播** 可唤醒线程,线程唤醒后,会进行获得锁的操作。当锁是互斥锁时,线程可能又会因无法获得锁而被阻塞。
90//! + 当线程的阻塞等待被中断时,会在 [`Err`] 中返回 [`CondError::Interrupt`] 。
91//! + 获得锁后,会在 [`Ok`] 中重新返回锁的 **守卫(Guard)** 。
92//! + 当发生错误,返回 [`Err`] 时,锁的 **守卫(Guard)** 被 **消费** ,生命周期结束,不再可用。
93//!
94//! 各种锁的 **等待** 条件量的方法:
95//!
96//! + 互斥锁: [`crate::xwos::lock::mtx::MutexGuard::wait()`]
97//! + 自旋锁: [`crate::xwos::lock::spinlock::SpinlockGuard::wait()`]
98//! + 顺序锁的独占读锁: [`crate::xwos::lock::seqlock::SeqlockGuard::wait()`]
99//! + 顺序锁的写锁: [`crate::xwos::lock::seqlock::SeqlockGuard::wait()`]
100//!
101//! ## 超时等待
102//!
103//! **超时等待** 的方法只可在 **线程** 上下文中使用,会 **消费** 锁的 **守卫(Guard)** ,然后线程阻塞等待条件量,等待时会指定一个唤醒时间点:
104//!
105//! + 通过 **单播** 或 **广播** 可唤醒线程,线程唤醒后,会进行获得锁的操作。
106//!   当锁是互斥锁时,线程可能又会因无法获得锁而被阻塞,但到指定的唤醒时间点时一定会超时唤醒。
107//! + 当线程的阻塞等待被中断时,会在 [`Err`] 中返回 [`CondError::Interrupt`] 。
108//! + 当到达指定的唤醒时间点,线程被唤醒,并返回 [`CondError::Timedout`] 。
109//! + 获得锁后,会在 [`Ok`] 中重新返回锁的 **守卫(Guard)** 。
110//! + 当发生错误,返回 [`Err`] 时,锁的 **守卫(Guard)** 被 **消费** ,生命周期结束,不再可用。
111//!
112//! 各种锁的 **等待** 条件量的方法:
113//!
114//! + 互斥锁: [`crate::xwos::lock::mtx::MutexGuard::wait_to()`]
115//! + 自旋锁: [`crate::xwos::lock::spinlock::SpinlockGuard::wait_to()`]
116//! + 顺序锁的独占读锁: [`crate::xwos::lock::seqlock::SeqlockGuard::wait_to()`]
117//! + 顺序锁的写锁: [`crate::xwos::lock::seqlock::SeqlockGuard::wait_to()`]
118//!
119//! ## 不可中断等待
120//!
121//! **不可中断等待** 的方法只可在 **线程** 上下文中使用,会 **消费** 锁的 **守卫(Guard)** ,然后线程阻塞等待条件量,并且不可被中断:
122//!
123//! + 通过 **单播** 或 **广播** 可唤醒线程,线程唤醒后,会进行获得锁的操作。
124//!   当锁是互斥锁时,线程可能又会因无法获得锁而被阻塞,互斥锁的阻塞等待同样是不可被中断的。
125//! + 获得锁后,会在 [`Ok`] 中重新返回锁的 **守卫(Guard)** 。
126//! + 当发生错误,返回 [`Err`] 时,锁的 **守卫(Guard)** 被 **消费** ,生命周期结束,不再可用。
127//!
128//! 各种锁的 **等待** 条件量的方法:
129//!
130//! + 互斥锁: [`crate::xwos::lock::mtx::MutexGuard::wait_unintr()`]
131//! + 自旋锁: [`crate::xwos::lock::spinlock::SpinlockGuard::wait_unintr()`]
132//! + 顺序锁的独占读锁: [`crate::xwos::lock::seqlock::SeqlockGuard::wait_unintr()`]
133//! + 顺序锁的写锁: [`crate::xwos::lock::seqlock::SeqlockGuard::wait_unintr()`]
134//!
135//!
136//! # 绑定到信号选择器
137//!
138//! 条件量是 **同步对象** ,可以通过方法 [`Cond::bind()`] 将条件量绑定到信号选择器 [`Sel<M>`] 上,通过 [`Sel<M>`] ,单一线程可以同时等待多个不同的 **同步对象** 。
139//!
140//! 条件量采用 **非独占** 的方式进行绑定。
141//!
142//!
143//! # 示例
144//!
145//! [XWOS/xwam/xwrust-example/xwrust_example_cond](https://gitee.com/xwos/XWOS/blob/main/xwam/xwrust-example/xwrust_example_cond/src/lib.rs)
146//!
147//!
148//! [`static`]: <https://doc.rust-lang.org/std/keyword.static.html>
149//! [`alloc::sync::Arc`]: <https://doc.rust-lang.org/alloc/sync/struct.Arc.html>
150//! [`Ok`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Ok>
151//! [`Err`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
152//! [`Sel<M>`]: super::sel::Sel
153
154extern crate core;
155use core::ffi::*;
156use core::cell::UnsafeCell;
157
158use crate::types::*;
159use crate::errno::*;
160use crate::xwbmp::*;
161use crate::xwos::sync::sel::*;
162
163
164extern "C" {
165    pub(crate) fn xwrustffi_cond_init(cond: *mut XwosCond) -> XwEr;
166    pub(crate) fn xwrustffi_cond_fini(cond: *mut XwosCond) -> XwEr;
167    pub(crate) fn xwrustffi_cond_grab(cond: *mut XwosCond) -> XwEr;
168    pub(crate) fn xwrustffi_cond_put(cond: *mut XwosCond) -> XwEr;
169    pub(crate) fn xwrustffi_cond_get_tik(cond: *mut XwosCond) -> XwSq;
170    pub(crate) fn xwrustffi_cond_acquire(cond: *mut XwosCond, tik: XwSq) -> XwEr;
171    pub(crate) fn xwrustffi_cond_release(cond: *mut XwosCond, tik: XwSq) -> XwEr;
172    pub(crate) fn xwrustffi_cond_bind(cond: *mut XwosCond, sel: *mut c_void, pos: XwSq) -> XwEr;
173    pub(crate) fn xwrustffi_cond_unbind(cond: *mut XwosCond, sel: *mut c_void) -> XwEr;
174    pub(crate) fn xwrustffi_cond_freeze(cond: *mut XwosCond) -> XwEr;
175    pub(crate) fn xwrustffi_cond_thaw(cond: *mut XwosCond) -> XwEr;
176    pub(crate) fn xwrustffi_cond_broadcast(cond: *mut XwosCond) -> XwEr;
177    pub(crate) fn xwrustffi_cond_unicast(cond: *mut XwosCond) -> XwEr;
178    pub(crate) fn xwrustffi_cond_wait(cond: *mut XwosCond,
179                                      lock: *mut c_void, lktype: XwSq, lkdata: *mut c_void,
180                                      lkst: *mut XwSq) -> XwEr;
181    pub(crate) fn xwrustffi_cond_wait_to(cond: *mut XwosCond,
182                                         lock: *mut c_void, lktype: XwSq, lkdata: *mut c_void,
183                                         to: XwTm, lkst: *mut XwSq) -> XwEr;
184    pub(crate) fn xwrustffi_cond_wait_unintr(cond: *mut XwosCond,
185                                             lock: *mut c_void, lktype: XwSq, lkdata: *mut c_void,
186                                             lkst: *mut XwSq) -> XwEr;
187}
188
189/// 条件量的错误码
190#[derive(Debug)]
191pub enum CondError {
192    /// 没有错误
193    Ok(XwEr),
194    /// 条件量没有初始化
195    NotInit(XwEr),
196    /// 条件量已被冻结
197    AlreadyFrozen(XwEr),
198    /// 条件量已解冻
199    AlreadyThawed(XwEr),
200    /// 等待被中断
201    Interrupt(XwEr),
202    /// 等待超时
203    Timedout(XwEr),
204    /// 不在线程上下文内
205    NotThreadContext(XwEr),
206    /// 信号选择器的位置超出范围
207    OutOfSelPos(XwEr),
208    /// 条件量已经绑定
209    AlreadyBound(XwEr),
210    /// 信号选择器的位置被占用
211    SelPosBusy(XwEr),
212    /// 未知错误
213    Unknown(XwEr),
214}
215
216impl CondError {
217    /// 消费掉 `CondError` 自身,返回内部的错误码。
218    pub fn unwrap(self) -> XwEr {
219        match self {
220            Self::Ok(rc) => rc,
221            Self::NotInit(rc) => rc,
222            Self::AlreadyFrozen(rc) => rc,
223            Self::AlreadyThawed(rc) => rc,
224            Self::Interrupt(rc) => rc,
225            Self::Timedout(rc) => rc,
226            Self::NotThreadContext(rc) => rc,
227            Self::OutOfSelPos(rc) => rc,
228            Self::AlreadyBound(rc) => rc,
229            Self::SelPosBusy(rc) => rc,
230            Self::Unknown(rc) => rc,
231        }
232    }
233
234    /// 如果错误码是 [`CondError::Ok`] ,返回 `true` 。
235    pub const fn is_ok(&self) -> bool {
236        matches!(*self, Self::Ok(_))
237    }
238
239    /// 如果错误码不是 [`CondError::Ok`] ,返回 `true` 。
240    pub const fn is_err(&self) -> bool {
241        !self.is_ok()
242    }
243}
244
245/// 锁类型:无
246pub(crate) const XWOS_LK_NONE: XwSq = 0;
247/// 锁类型:互斥锁
248pub(crate) const XWOS_LK_MTX: XwSq = 1;
249/// 锁类型:自旋锁
250pub(crate) const XWOS_LK_SPLK: XwSq = 2;
251/// 锁类型:顺序写锁
252pub(crate) const XWOS_LK_SQLK_WR: XwSq = 3;
253/// 锁类型:独占顺序读锁
254pub(crate) const XWOS_LK_SQLK_RDEX: XwSq = 4;
255/// 锁类型:抽象回调锁
256pub(crate) const XWOS_LK_CALLBACK: XwSq = 5;
257
258
259/// 锁状态:锁定
260pub(crate) const XWOS_LKST_LOCKED: XwSq = 0;
261/// 锁状态:未锁定
262pub(crate) const XWOS_LKST_UNLOCKED: XwSq = 1;
263
264/// XWOS条件量对象占用的内存大小
265#[cfg(target_pointer_width = "32")]
266pub const SIZEOF_XWOS_COND: usize = 64;
267
268/// XWOS条件量对象占用的内存大小
269#[cfg(target_pointer_width = "64")]
270pub const SIZEOF_XWOS_COND: usize = 128;
271
272/// 用于构建条件量的内存数组类型
273#[repr(C)]
274#[cfg_attr(target_pointer_width = "32", repr(align(8)))]
275#[cfg_attr(target_pointer_width = "64", repr(align(16)))]
276pub(crate) struct XwosCond {
277    pub(crate) obj: [u8; SIZEOF_XWOS_COND],
278}
279
280/// 用于构建条件量的内存数组常量
281///
282/// 此常量的作用是告诉编译器条件量对象需要多大的内存。
283pub(crate) const XWOS_COND_INITIALIZER: XwosCond = XwosCond {
284    obj: [0; SIZEOF_XWOS_COND],
285};
286
287/// 条件量对象结构体
288pub struct Cond {
289    /// 用于初始化XWOS条件量对象的内存空间
290    pub(crate) cond: UnsafeCell<XwosCond>,
291    /// 条件量对象的标签
292    pub(crate) tik: UnsafeCell<XwSq>,
293}
294
295unsafe impl Send for Cond {}
296unsafe impl Sync for Cond {}
297
298impl Drop for Cond {
299    fn drop(&mut self) {
300        unsafe {
301            xwrustffi_cond_fini(self.cond.get());
302        }
303    }
304}
305
306impl Cond {
307    /// 新建条件量对象
308    ///
309    /// 此方法是编译期方法。
310    ///
311    /// # 示例
312    ///
313    /// + 具有 [`static`] 约束的全局变量全局变量:
314    ///
315    /// ```rust
316    /// use xwrust::xwos::sync::cond::*;
317    ///
318    /// static GLOBAL_COND: Cond  = Cond::new();
319    /// ```
320    ///
321    /// + 在heap中创建:
322    ///
323    /// ```rust
324    /// extern crate alloc;
325    /// use alloc::sync::Arc;
326    ///
327    /// pub fn xwrust_example_cond() {
328    ///     let cond = Arc::new(Cond::new());
329    /// }
330    /// ```
331    ///
332    /// [`static`]: https://doc.rust-lang.org/std/keyword.static.html
333    pub const fn new() -> Self {
334        Self {
335            cond: UnsafeCell::new(XWOS_COND_INITIALIZER),
336            tik: UnsafeCell::new(0),
337        }
338    }
339}
340
341impl Cond {
342    /// 初始化条件量对象
343    ///
344    /// 条件量对象必须调用此方法一次,方可正常使用。
345    ///
346    /// # 上下文
347    ///
348    /// + 任意
349    ///
350    /// # 示例
351    ///
352    /// ```rust
353    /// use xwrust::xwos::sync::cond::*;
354    ///
355    /// static GLOBAL_COND: Cond = Cond::new();
356    ///
357    /// pub unsafe extern "C" fn xwrust_main() {
358    ///     // ...省略...
359    ///     GLOBAL_COND.init();
360    ///     // 从此处开始 GLOBAL_COND 可正常使用
361    /// }
362    /// ```
363    pub fn init(&self) {
364        unsafe {
365            let rc = xwrustffi_cond_acquire(self.cond.get(), *self.tik.get());
366            if rc == 0 {
367                xwrustffi_cond_put(self.cond.get());
368            } else {
369                xwrustffi_cond_init(self.cond.get());
370                *self.tik.get() = xwrustffi_cond_get_tik(self.cond.get());
371            }
372        }
373    }
374
375    /// 冻结条件量
376    ///
377    /// 条件量被冻结后,可被线程等待,但被能被单播 [`Cond::unicast()`] 或广播 [`Cond::broadcast()`] 。
378    ///
379    /// # 上下文
380    ///
381    /// + 任意
382    ///
383    /// # 错误码
384    ///
385    /// + [`CondError::Ok`] 没有错误
386    /// + [`CondError::NotInit`] 条件量没有初始化
387    /// + [`CondError::AlreadyFrozen`] 条件量已被冻结
388    ///
389    /// # 示例
390    ///
391    /// ```rust
392    /// use xwrust::xwos::sync::cond::*;
393    ///
394    /// pub unsafe extern "C" fn xwrust_main() {
395    ///     // ...省略...
396    ///     condvar: Cond = Cond::new();
397    ///     condvar.init();
398    ///     condvar.freeze();
399    /// }
400    /// ```
401    pub fn freeze(&self) -> CondError {
402        unsafe {
403            let mut rc = xwrustffi_cond_acquire(self.cond.get(), *self.tik.get());
404            if rc == 0 {
405                rc = xwrustffi_cond_freeze(self.cond.get());
406                xwrustffi_cond_put(self.cond.get());
407                if XWOK == rc {
408                    CondError::Ok(rc)
409                } else if -EALREADY == rc {
410                    CondError::AlreadyFrozen(rc)
411                } else {
412                    CondError::Unknown(rc)
413                }
414            } else {
415                CondError::NotInit(rc)
416            }
417        }
418    }
419
420    /// 解冻条件量
421    ///
422    /// 被冻结的条件量解冻后,可被单播 [`Cond::unicast()`] 或广播 [`Cond::broadcast()`] 。
423    ///
424    /// # 上下文
425    ///
426    /// + 任意
427    ///
428    /// # 错误码
429    ///
430    /// + [`CondError::Ok`] 没有错误
431    /// + [`CondError::NotInit`] 条件量没有初始化
432    /// + [`CondError::AlreadyThawed`] 条件量已解冻
433    ///
434    /// # 示例
435    ///
436    /// ```rust
437    /// use xwrust::xwos::sync::cond::*;
438    ///
439    /// pub unsafe extern "C" fn xwrust_main() {
440    ///     // ...省略...
441    ///     condvar: Cond = Cond::new();
442    ///     condvar.init();
443    ///     condvar.freeze(); // 冻结
444    ///     // ...省略...
445    ///     condvar.thaw(); // 解冻
446    /// }
447    /// ```
448    pub fn thaw(&self) -> CondError {
449        unsafe {
450            let mut rc = xwrustffi_cond_acquire(self.cond.get(), *self.tik.get());
451            if rc == 0 {
452                rc = xwrustffi_cond_thaw(self.cond.get());
453                xwrustffi_cond_put(self.cond.get());
454                if XWOK == rc {
455                    CondError::Ok(rc)
456                } else if -EALREADY == rc {
457                    CondError::AlreadyThawed(rc)
458                } else {
459                    CondError::Unknown(rc)
460                }
461            } else {
462                CondError::NotInit(rc)
463            }
464        }
465    }
466
467    /// 单播条件量对象
468    ///
469    /// 只会唤醒第一个线程,阻塞线程的队列使用的是先进先出(FIFO)算法 。
470    ///
471    /// # 上下文
472    ///
473    /// + 任意
474    ///
475    /// # 错误码
476    ///
477    /// + [`CondError::Ok`] 没有错误
478    /// + [`CondError::NotInit`] 条件量没有初始化
479    /// + [`CondError::AlreadyFrozen`] 条件量已被冻结
480    ///
481    /// # 示例
482    ///
483    /// ```rust
484    /// use xwrust::xwos::sync::cond::*;
485    ///
486    /// pub unsafe extern "C" fn xwrust_main() {
487    ///     // ...省略...
488    ///     condvar: Cond = Cond::new();
489    ///     condvar.init();
490    ///     // ...省略...
491    ///     condvar.unicast();
492    /// }
493    /// ```
494    pub fn unicast(&self) -> CondError {
495        unsafe {
496            let mut rc = xwrustffi_cond_acquire(self.cond.get(), *self.tik.get());
497            if rc == 0 {
498                rc = xwrustffi_cond_unicast(self.cond.get());
499                xwrustffi_cond_put(self.cond.get());
500                if XWOK == rc {
501                    CondError::Ok(rc)
502                } else if -ENEGATIVE == rc {
503                    CondError::AlreadyFrozen(rc)
504                } else {
505                    CondError::Unknown(rc)
506                }
507            } else {
508                CondError::NotInit(rc)
509            }
510        }
511    }
512
513    /// 广播条件量
514    ///
515    /// 阻塞队列中的线程会全部被唤醒。
516    ///
517    /// # 上下文
518    ///
519    /// + 任意
520    ///
521    /// # 错误码
522    ///
523    /// + [`CondError::Ok`] 没有错误
524    /// + [`CondError::NotInit`] 条件量没有初始化
525    /// + [`CondError::AlreadyFrozen`] 条件量已被冻结
526    ///
527    /// # 示例
528    ///
529    /// ```rust
530    /// use xwrust::xwos::sync::cond::*;
531    ///
532    /// pub unsafe extern "C" fn xwrust_main() {
533    ///     // ...省略...
534    ///     condvar: Cond = Cond::new();
535    ///     condvar.init();
536    ///     // ...省略...
537    ///     condvar.broadcast();
538    /// }
539    /// ```
540    pub fn broadcast(&self) -> CondError {
541        unsafe {
542            let mut rc = xwrustffi_cond_acquire(self.cond.get(), *self.tik.get());
543            if rc == 0 {
544                rc = xwrustffi_cond_broadcast(self.cond.get());
545                xwrustffi_cond_put(self.cond.get());
546                if XWOK == rc {
547                    CondError::Ok(rc)
548                } else if -ENEGATIVE == rc {
549                    CondError::AlreadyFrozen(rc)
550                } else {
551                    CondError::Unknown(rc)
552                }
553            } else {
554                CondError::NotInit(rc)
555            }
556        }
557    }
558
559    /// 绑定条件量对象到信号选择器
560    ///
561    /// + 条件量绑定到信号选择器上时,采用 **非独占** 的方式进行绑定。
562    /// + 绑定成功,通过 [`Ok()`] 返回 [`CondSel<'a, M>`] 。
563    /// + 如果位置已被其他 **同步对象** 以 **独占** 的方式占领,通过 [`Err()`] 返回 [`CondError::SelPosBusy`] 。
564    /// + 当指定的位置超出范围(例如 [`Sel<M>`] 只有8个位置,用户偏偏要绑定到位置9 ),通过 [`Err()`] 返回 [`CondError::OutOfSelPos`] 。
565    /// + 重复绑定,通过 [`Err()`] 返回 [`CondError::AlreadyBound`] 。
566    ///
567    /// [`CondSel<'a, M>`] 中包含条件量的绑定信息。 [`CondSel<'a, M>`] 与 [`Cond`] 与 [`Sel<M>`] 具有相同的生命周期约束 `'a` 。
568    /// [`CondSel::selected()`] 可用来判断条件量是否被选择。当 [`CondSel<'a, M>`] [`drop()`] 时,会自动解绑。
569    ///
570    /// # 参数说明
571    ///
572    /// + sel: 信号选择器的引用
573    /// + pos: 位置
574    ///
575    /// # 上下文
576    ///
577    /// + 任意
578    ///
579    /// # 错误码
580    ///
581    /// + [`CondError::OutOfSelPos`] 信号选择器的位置超出范围
582    /// + [`CondError::AlreadyBound`] 条件量已经绑定
583    /// + [`CondError::SelPosBusy`] 信号选择器的位置被占用
584    ///
585    /// # 示例
586    ///
587    /// ```rust
588    /// pub fn xwrust_example_sel() {
589    ///     // ...省略...
590    ///     let cond0 = Arc::new(Cond::new());
591    ///     cond0.init();
592    ///     let cond0sel = match cond0.bind(&sel, 0) {
593    ///         Ok(s) => { // 绑定成功,`s` 为 `CondSel`
594    ///             s
595    ///         },
596    ///         Err(e) => { // 绑定失败,`e` 为 `SelError`
597    ///             return;
598    ///         }
599    ///     };
600    ///     // ...省略...
601    /// }
602    /// ```
603    ///
604    /// [`CondSel<'a, M>`]: CondSel
605    /// [`Ok()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Ok>
606    /// [`Err()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
607    /// [`Sel<M>`]: super::sel::Sel
608    /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
609    pub fn bind<'a, const M: XwSz>(&'a self, sel: &'a Sel<M>, pos: XwSq)
610                                   -> Result<CondSel<'a, M>, CondError>
611    where
612        [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
613    {
614        unsafe {
615            let mut rc = xwrustffi_cond_acquire(self.cond.get(), *self.tik.get());
616            if rc == 0 {
617                rc = xwrustffi_cond_bind(self.cond.get(), sel.sel.get() as _, pos);
618                if XWOK == rc {
619                    Ok(CondSel {
620                        cond: self,
621                        sel: sel,
622                        pos: pos,
623                    })
624                } else if -ECHRNG == rc {
625                    Err(CondError::OutOfSelPos(rc))
626                } else if -EALREADY == rc {
627                    Err(CondError::AlreadyBound(rc))
628                } else if -EBUSY == rc {
629                    Err(CondError::SelPosBusy(rc))
630                } else {
631                    Err(CondError::Unknown(rc))
632                }
633            } else {
634                Err(CondError::NotInit(rc))
635            }
636        }
637    }
638}
639
640/// 条件量的选择子
641///
642/// `CondSel<'a, M>` 与 [`Cond`] 与 [`Sel<M>`] 具有相同的生命周期约束 `'a` 。因为 `CondSel<'a, M>` 中包含了 [`Cond`] 与 [`Sel<M>`] 的引用。
643///
644/// `CondSel<'a, M>` 中包含了绑定的位置信息,条件量采用 **非独占** 的方式进行绑定。
645///
646/// [`CondSel::selected()`] 可用来判断条件量是否被选择。
647///
648/// 当 `CondSel<'a, M>` 被 [`drop()`] 时,会自动将 [`Cond`] 从 [`Sel<M>`] 解绑。
649///
650/// [`Sel<M>`]: super::sel::Sel
651/// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
652pub struct CondSel<'a, const M: XwSz>
653where
654    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
655{
656    cond: &'a Cond,
657    sel: &'a Sel<M>,
658    pos: XwSq,
659}
660
661unsafe impl<'a, const M: XwSz> Send for CondSel<'a, M>
662where
663    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
664{}
665
666unsafe impl<'a, const M: XwSz> Sync for CondSel<'a, M>
667where
668    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
669{}
670
671impl<'a, const M: XwSz> Drop for CondSel<'a, M>
672where
673    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
674{
675    fn drop(&mut self) {
676        unsafe {
677            xwrustffi_cond_unbind(self.cond.cond.get(), self.sel.sel.get() as _);
678            xwrustffi_cond_put(self.cond.cond.get());
679        }
680    }
681}
682
683impl<'a, const M: XwSz> CondSel<'a, M>
684where
685    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
686{
687    /// 判断触发的 **选择信号** 是否包括此条件量
688    ///
689    /// # 示例
690    ///
691    /// ```rust
692    ///     let msk = Bmp::<8>::new(); // 8位位图
693    ///     msk.s1all(); // 掩码为0xFF
694    ///     loop {
695    ///         let res = sel.select(&msk);
696    ///         match res {
697    ///             Ok(t) => { // 信号选择器上有 **选择信号** , `t` 为 **选择信号** 的位图。
698    ///                 if cond0sel.selected(&t) { // 条件量0被选择到
699    ///                 }
700    ///                 if cond1sel.selected(&t) { // 条件量1被选择到
701    ///                 }
702    ///             },
703    ///             Err(e) => { // 等待信号选择器失败,`e` 为 `SelError`
704    ///                 break;
705    ///             },
706    ///         }
707    ///     }
708    /// ```
709    pub fn selected(&self, trg: &Bmp<M>) -> bool {
710        trg.t1i(self.pos)
711    }
712}