Skip to main content

xwrust/xwos/sync/
flg.rs

1//! XWOS RUST:事件标志
2//! ========
3//!
4//! 事件标志使用位图来管理一组事件,位图中的每个位代表一个事件,
5//! 当一个或多个事件状态发生变化时,事件对应的位也会发生变化,并唤醒正在等待的线程。
6//! 线程唤醒后,就可从事件位图中获取事件的状态。
7//!
8//! + 线程可以等待位图中的事件位被置 **1** ,也可以等待事件位被清 **0** 。
9//! + 线程可以等待位图中的事件位同时被置 **1** (事件与事件之间是逻辑 **与** 的关系),也可以等待其中任意一个位被置 **1** (事件与事件之间是逻辑 **或** 的关系)。
10//! + 线程可以等待位图中的事件位同时被清 **0** (事件与事件之间是逻辑 **与** 的关系),也可以等待其中任意一个位被清 **0** (事件与事件之间是逻辑 **或** 的关系)。
11//! + 线程可以选择是否 **消费** 事件。 **消费** 事件是指,当事件到来,线程被唤醒时,可以选择是否 **清除** 事件。
12//! + 线程可以等待事件标志位发生 **翻转** , **翻转** 是指事件标志位由 **1** 变为 **0** ,或由 **0** 变为 **1** 。
13//!
14//!
15//! # 创建
16//!
17//! XWOS RUST的事件标志可使用 [`Flg::new()`] 创建。
18//!
19//! + 可以创建具有静态生命周期 [`static`] 约束的全局变量:
20//!
21//! ```rust
22//! use xwrust::xwos::sync::flg::*;
23//!
24//! static GLOBAL_FLG: Flg<8> = Flg::new();
25//! ```
26//!
27//! + 也可以使用 [`alloc::sync::Arc`] 在heap中创建:
28//!
29//! ```rust
30//! extern crate alloc;
31//! use alloc::sync::Arc;
32//!
33//! use xwrust::xwos::sync::flg::*;
34//!
35//! pub fn xwrust_example_flg() {
36//!     let flg = Arc::new(Flg::<8>::new());
37//! }
38//! ```
39//!
40//!
41//! # 初始化
42//!
43//! 无论以何种方式创建的事件标志,都必须在使用前调用 [`Flg::init()`] 进行初始化:
44//!
45//! ```rust
46//! pub fn xwrust_example_flg() {
47//!     GLOBAL_FLG.init();
48//!     flg.init();
49//! }
50//! ```
51//!
52//!
53//! # 产生事件
54//!
55//! + [`Flg::s1m()`] 同时设置多个事件标志位
56//! + [`Flg::s1i()`] 设置单个事件标志位
57//! + [`Flg::c0m()`] 同时清除多个事件标志位
58//! + [`Flg::c0i()`] 清除单个事件标志位
59//! + [`Flg::x1m()`] 同时翻转多个事件标志位
60//! + [`Flg::x1i()`] 翻转单个事件标志位
61//!
62//! 产生事件的方法,除了会修改事件标志位图的状态,还会通过 **广播** 唤醒所有正在等待的线程。
63//! 然后,线程通过比对位图状态,确定事件是否已经满足触发条件。
64//! 若满足触发条件,就退出等待;若未满足触发条件,重新进入阻塞等待状态。
65//!
66//!
67//! # 等待事件的方法
68//!
69//! + [`Flg::wait()`] 可用于等待事件。
70//! + [`Flg::wait_to()`] 可用于限时等待事件。
71//! + [`Flg::trywait()`] 可用于检测事件。
72//!
73//! ## 事件的触发条件
74//!
75//! 等待事件时,可通过参数 `tg` 指明事件的触发条件。事件的触发条件分为两类。
76//!
77//! ### 电平触发
78//!
79//! **电平触发** 源于数字电路,是一种类比概念,是指事件位图的特定状态( **1** 或 **0** )所产生的触发事件,包括:
80//!
81//! + [`Trigger::SetAll`] 所有事件位被置 **1** 触发
82//! + [`Trigger::SetAny`] 任意事件位被置 **1** 触发
83//! + [`Trigger::ClearAll`] 所有事件位被清 **0** 触发
84//! + [`Trigger::ClearAny`] 任意事件位被清 **0** 触发
85//!
86//! **电平触发** 时,可在线程读取事件位图后,**清除** 事件触发条件。
87//!
88//! ### 边沿触发
89//!
90//! **边沿触发** 源于数字电路,是一种类比概念,是指事件状态发生改变( **1** 变 **0** 或 **0** 变 **1** )时产生的唤醒信号,包括:
91//!
92//! + [`Trigger::SetAll`] 所有事件位发生翻转触发
93//! + [`Trigger::SetAny`] 任意事件位发生翻转触发
94//!
95//! **边沿触发** 时,事件的触发条件不需要清除。
96//! **边沿触发** 时,必须要有一个初始状态,就像数字电路一样:
97//!
98//! + 当位的初始值为 **0** (低电平),然后跳变到 **1** (高电平)的瞬间被称为上升沿。此时触发的事件被称为上升沿触发。
99//! + 当位的初始值为 **1** (高电平),然后跳变到 **0** (低电平)的瞬间被称为下降沿。此时触发的事件被称为下降沿触发。
100//!
101//! ## 清除事件
102//!
103//! + 当采用 **电平触发** 时,需要在读取事件位图后 **清除** 事件标志位,否则事件会一直处于触发状态。
104//!   可以在调用等待事件的方法时,指定参数 `consumption` 为 `true` 。
105//!   **清除** 的含义是:
106//!   + 当线程等待的是位图中的事件位被置 **1** , **清除** 是指将这些位清 **0** ;
107//!   + 当线程等待的是位图中的事件位被清 **0** , **清除** 是指将这些位置 **1** ;
108//! + 当采用 **边沿触发** 时,不需要 **清除** 事件标志位。
109//!
110//!
111//! # 读取事件
112//!
113//! 用户可以通过方法 [`Flg::read()`] 直接读取事件的位图状态。此函数立即返回,不会阻塞。
114//!
115//! # 获取事件标志中事件槽的数量
116//!
117//! 可以通过方法 [`Flg::get_num()`] 获取事件标志中事件槽的数量。
118//!
119//!
120//! # 绑定到信号选择器
121//!
122//! 事件标志是 **同步对象** ,可以通过方法 [`Flg::bind()`] 将事件标志绑定到信号选择器 [`Sel<M>`] 上,通过 [`Sel<M>`] ,单一线程可以同时等待多个不同的 **同步对象** 。
123//!
124//! 事件标志采用 **非独占** 的方式进行绑定。
125//!
126//!
127//! # 示例
128//!
129//! [XWOS/xwam/xwrust-example/xwrust_example_flg](https://gitee.com/xwos/XWOS/blob/main/xwam/xwrust-example/xwrust_example_flg/src/lib.rs)
130//!
131//!
132//! [`static`]: <https://doc.rust-lang.org/std/keyword.static.html>
133//! [`alloc::sync::Arc`]: <https://doc.rust-lang.org/alloc/sync/struct.Arc.html>
134//! [`Sel<M>`]: super::sel::Sel
135
136extern crate core;
137use core::ffi::*;
138use core::cell::UnsafeCell;
139
140use crate::types::*;
141use crate::errno::*;
142use crate::xwbmp::*;
143use crate::xwos::sync::sel::*;
144
145
146extern "C" {
147    pub(crate) fn xwrustffi_flg_init(flg: *mut c_void, num: XwSz, bmp: *mut XwBmp, msk: *mut XwBmp) -> XwEr;
148    pub(crate) fn xwrustffi_flg_fini(flg: *mut c_void) -> XwEr;
149    pub(crate) fn xwrustffi_flg_grab(flg: *mut c_void) -> XwEr;
150    pub(crate) fn xwrustffi_flg_put(flg: *mut c_void) -> XwEr;
151    pub(crate) fn xwrustffi_flg_get_tik(flg: *mut c_void) -> XwSq;
152    pub(crate) fn xwrustffi_flg_acquire(flg: *mut c_void, tik: XwSq) -> XwEr;
153    pub(crate) fn xwrustffi_flg_release(flg: *mut c_void, tik: XwSq) -> XwEr;
154    pub(crate) fn xwrustffi_flg_bind(flg: *mut c_void, sel: *mut c_void, pos: XwSq) -> XwEr;
155    pub(crate) fn xwrustffi_flg_unbind(flg: *mut c_void, sel: *mut c_void) -> XwEr;
156    pub(crate) fn xwrustffi_flg_read(flg: *mut c_void, out: *mut XwBmp) -> XwEr;
157    pub(crate) fn xwrustffi_flg_s1m(flg: *mut c_void, msk: *mut XwBmp) -> XwEr;
158    pub(crate) fn xwrustffi_flg_s1i(flg: *mut c_void, pos: XwSq) -> XwEr;
159    pub(crate) fn xwrustffi_flg_c0m(flg: *mut c_void, msk: *mut XwBmp) -> XwEr;
160    pub(crate) fn xwrustffi_flg_c0i(flg: *mut c_void, pos: XwSq) -> XwEr;
161    pub(crate) fn xwrustffi_flg_x1m(flg: *mut c_void, msk: *mut XwBmp) -> XwEr;
162    pub(crate) fn xwrustffi_flg_x1i(flg: *mut c_void, pos: XwSq) -> XwEr;
163    pub(crate) fn xwrustffi_flg_wait(flg: *mut c_void, tg: XwSq, consumption: bool,
164                                     origin: *mut XwBmp, msk: *mut XwBmp) -> XwEr;
165    pub(crate) fn xwrustffi_flg_wait_to(flg: *mut c_void, tg: XwSq, consumption: bool,
166                                        origin: *mut XwBmp, msk: *mut XwBmp, to: XwTm) -> XwEr;
167    pub(crate) fn xwrustffi_flg_trywait(flg: *mut c_void, tg: XwSq, consumption: bool,
168                                        origin: *mut XwBmp, msk: *mut XwBmp) -> XwEr;
169    pub(crate) fn xwrustffi_flg_wait_unintr(flg: *mut c_void, tg: XwSq, consumption: bool,
170                                            origin: *mut XwBmp, msk: *mut XwBmp) -> XwEr;
171}
172
173/// 事件标志的错误码
174#[derive(Debug)]
175pub enum FlgError {
176    /// 没有错误
177    Ok(XwEr),
178    /// 事件标志没有初始化
179    NotInit(XwEr),
180    /// 位置超出范围
181    OutOfRange(XwEr),
182    /// 等待被中断
183    Interrupt(XwEr),
184    /// 等待超时
185    Timedout(XwEr),
186    /// 没有检测到事件
187    NoEvent(XwEr),
188    /// 不在线程上下文内
189    NotThreadContext(XwEr),
190    /// 信号选择器的位置超出范围
191    OutOfSelPos(XwEr),
192    /// 事件标志已经绑定
193    AlreadyBound(XwEr),
194    /// 信号选择器的位置被占用
195    SelPosBusy(XwEr),
196    /// 未知错误
197    Unknown(XwEr),
198}
199
200impl FlgError {
201    /// 消费掉 `FlgError` 自身,返回内部的错误码。
202    pub fn unwrap(self) -> XwEr {
203        match self {
204            Self::Ok(rc) => rc,
205            Self::NotInit(rc) => rc,
206            Self::OutOfRange(rc) => rc,
207            Self::Interrupt(rc) => rc,
208            Self::Timedout(rc) => rc,
209            Self::NoEvent(rc) => rc,
210            Self::NotThreadContext(rc) => rc,
211            Self::OutOfSelPos(rc) => rc,
212            Self::AlreadyBound(rc) => rc,
213            Self::SelPosBusy(rc) => rc,
214            Self::Unknown(rc) => rc,
215        }
216    }
217
218    /// 如果错误码是 [`FlgError::Ok`] ,返回 `true` 。
219    pub const fn is_ok(&self) -> bool {
220        matches!(*self, Self::Ok(_))
221    }
222
223    /// 如果错误码不是 [`FlgError::Ok`] ,返回 `true` 。
224    pub const fn is_err(&self) -> bool {
225        !self.is_ok()
226    }
227}
228
229/// 触发条件
230pub enum Trigger {
231    /// 所有事件位被置 **1** 触发
232    SetAll = 0,
233    /// 任意事件位被置 **1** 触发
234    SetAny = 1,
235    /// 所有事件位被清 **0** 触发
236    ClearAll = 2,
237    /// 任意事件位被清 **0** 触发
238    ClearAny = 3,
239    /// 所有事件位发生翻转触发
240    ToggleAll = 4,
241    /// 任意事件位发生翻转触发
242    ToggleAny = 5,
243}
244
245/// XWOS事件标志对象占用的内存大小
246#[cfg(target_pointer_width = "32")]
247pub const SIZEOF_XWOS_FLG: usize = 64;
248
249/// XWOS事件标志对象占用的内存大小
250#[cfg(target_pointer_width = "64")]
251pub const SIZEOF_XWOS_FLG: usize = 128;
252
253/// 用于构建事件标志的内存数组类型
254#[repr(C)]
255#[cfg_attr(target_pointer_width = "32", repr(align(8)))]
256#[cfg_attr(target_pointer_width = "64", repr(align(16)))]
257pub(crate) struct XwosFlg<const N: XwSz>
258where
259    [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
260{
261    pub(crate) obj: [u8; SIZEOF_XWOS_FLG],
262    pub(crate) bmp: [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
263    pub(crate) msk: [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
264}
265
266/// 事件标志对象结构体
267pub struct Flg<const N: XwSz>
268where
269    [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
270{
271    /// 用于初始化XWOS事件标志对象的内存空间
272    pub(crate) flg: UnsafeCell<XwosFlg<N>>,
273    /// 事件标志对象的标签
274    pub(crate) tik: UnsafeCell<XwSq>,
275}
276
277unsafe impl<const N: XwSz> Send for Flg<N>
278where
279    [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
280{}
281
282unsafe impl<const N: XwSz> Sync for Flg<N>
283where
284    [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
285{}
286
287impl<const N: XwSz> Drop for Flg<N>
288where
289    [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
290{
291    fn drop(&mut self) {
292        unsafe {
293            xwrustffi_flg_fini(self.flg.get() as _);
294        }
295    }
296}
297
298impl<const N: XwSz> Flg<N>
299where
300    [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
301{
302    /// 新建事件标志对象
303    ///
304    /// 此方法是编译期方法。
305    ///
306    /// # 示例
307    ///
308    /// + 具有 [`static`] 约束的全局变量全局变量:
309    ///
310    /// ```rust
311    /// use xwrust::xwos::sync::flg::*;
312    ///
313    /// static GLOBAL_FLG: Flg<8> = Flg::new();
314    /// ```
315    ///
316    /// + 在heap中创建:
317    ///
318    /// ```rust
319    /// extern crate alloc;
320    /// use alloc::sync::Arc;
321    ///
322    /// pub fn xwrust_example_flg() {
323    ///     let flg = Arc::new(Flg::<8>::new());
324    /// }
325    /// ```
326    ///
327    /// [`static`]: https://doc.rust-lang.org/std/keyword.static.html
328    pub const fn new() -> Self {
329        Self {
330            flg: UnsafeCell::new(XwosFlg {
331                obj: [0; SIZEOF_XWOS_FLG],
332                bmp: [0; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
333                msk: [0; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
334            }),
335            tik: UnsafeCell::new(0),
336        }
337    }
338
339    /// 初始化事件标志对象
340    ///
341    /// 事件标志对象必须调用此方法一次,方可正常使用。
342    ///
343    /// # 上下文
344    ///
345    /// + 任意
346    ///
347    /// # 示例
348    ///
349    /// ```rust
350    /// use xwrust::xwos::sync::flg::*;
351    ///
352    /// static GLOBAL_FLG: Flg<8> = Flg::new();
353    ///
354    /// pub fn xwrust_example_flg() {
355    ///     // ...省略...
356    ///     GLOBAL_FLG.init();
357    ///     // 从此处开始 GLOBAL_FLG 可正常使用
358    /// }
359    /// ```
360    pub fn init(&self) {
361        unsafe {
362            let rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
363            if rc == 0 {
364                xwrustffi_flg_put(self.flg.get() as _);
365            } else {
366                xwrustffi_flg_init(self.flg.get() as _,
367                                  N,
368                                  &mut (*self.flg.get()).bmp as _,
369                                  &mut (*self.flg.get()).msk as _);
370                *self.tik.get() = xwrustffi_flg_get_tik(self.flg.get() as _);
371            }
372        }
373    }
374
375    /// 获取事件标志中事件槽的数量
376    pub const fn get_num(&self) -> XwSz {
377        N
378    }
379
380    /// 读取事件标志位图的值
381    ///
382    /// 直接读取位图的值,不会等待,也不会改变位图的状态。
383    pub fn read(&self) -> Result<Bmp<N>, FlgError> {
384        unsafe {
385            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
386            if rc == 0 {
387                let out = Bmp::<N>::new();
388                rc = xwrustffi_flg_read(self.flg.get() as _, out.bmp.get() as _,);
389                xwrustffi_flg_put(self.flg.get() as _);
390                if XWOK == rc {
391                    Ok(out)
392                } else {
393                    Err(FlgError::Unknown(rc))
394                }
395            } else {
396                Err(FlgError::NotInit(rc))
397            }
398        }
399    }
400
401    /// 同时设置多个事件标志位
402    ///
403    /// + 此RustAPI会将事件标志位图中,被掩码 `msk` 覆盖的位全部设置为 **1** ,
404    ///   然后 **广播** 所有正在等待的线程。
405    /// + 线程唤醒后通过比对位图状态,确定事件是否已经满足触发条件,
406    ///   若满足触发条件,就退出等待;若未满足触发条件,重新进入阻塞等待状态。
407    ///
408    /// # 参数说明
409    ///
410    /// + msk: 事件的位图掩码
411    pub fn s1m(&self, msk: &Bmp<N>) -> FlgError {
412        unsafe {
413            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
414            if rc == 0 {
415                rc = xwrustffi_flg_s1m(self.flg.get() as _, msk.bmp.get() as _);
416                xwrustffi_flg_put(self.flg.get() as _);
417                if XWOK == rc {
418                    FlgError::Ok(rc)
419                } else {
420                    FlgError::Unknown(rc)
421                }
422            } else {
423                FlgError::NotInit(rc)
424            }
425        }
426    }
427
428    /// 设置单个事件标志位
429    ///
430    /// + 此CAPI会将事件标志位图中,序号为 `pos` 的单个位设置为 **1** ,
431    ///   然后 **广播** 所有正在等待的线程。
432    /// + 线程唤醒后通过比对位图状态,确定事件是否已经满足触发条件,
433    ///   若满足触发条件,就退出等待;若未满足触发条件,重新进入阻塞等待状态。
434    ///
435    /// # 参数说明
436    ///
437    /// + pos: 事件的序号
438    pub fn s1i(&self, pos: XwSq) -> FlgError {
439        unsafe {
440            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
441            if rc == 0 {
442                rc = xwrustffi_flg_s1i(self.flg.get() as _, pos);
443                xwrustffi_flg_put(self.flg.get() as _);
444                if XWOK == rc {
445                    FlgError::Ok(rc)
446                } else {
447                    FlgError::Unknown(rc)
448                }
449            } else {
450                FlgError::NotInit(rc)
451            }
452        }
453    }
454
455    /// 同时清除多个事件标志位
456    ///
457    /// + 此CAPI会将事件标志位图中,被掩码 `msk` 覆盖的位全部清 **0** ,
458    ///   然后 **广播** 所有正在等待的线程。
459    /// + 线程唤醒后通过比对位图状态,确定事件是否已经满足触发条件,
460    ///   若满足触发条件,就退出等待;若未满足触发条件,重新进入阻塞等待状态。
461    ///
462    /// # 参数说明
463    ///
464    /// + msk: 事件的位图掩码
465    pub fn c0m(&self, msk: &Bmp<N>) -> FlgError {
466        unsafe {
467            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
468            if rc == 0 {
469                rc = xwrustffi_flg_c0m(self.flg.get() as _, msk.bmp.get() as _);
470                xwrustffi_flg_put(self.flg.get() as _);
471                if XWOK == rc {
472                    FlgError::Ok(rc)
473                } else {
474                    FlgError::Unknown(rc)
475                }
476            } else {
477                FlgError::NotInit(rc)
478            }
479        }
480    }
481
482    /// 清除单个事件标志位
483    ///
484    /// + 此CAPI会将事件标志位图中,序号为 `pos` 的单个位清 **0** ,
485    ///   然后 **广播** 所有正在等待的线程。
486    /// + 线程唤醒后通过比对位图状态,确定事件是否已经满足触发条件,
487    ///   若满足触发条件,就退出等待;若未满足触发条件,重新进入阻塞等待状态。
488    ///
489    /// # 参数说明
490    ///
491    /// + pos: 事件的序号
492    pub fn c0i(&self, pos: XwSq) -> FlgError {
493        unsafe {
494            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
495            if rc == 0 {
496                rc = xwrustffi_flg_c0i(self.flg.get() as _, pos);
497                xwrustffi_flg_put(self.flg.get() as _);
498                if XWOK == rc {
499                    FlgError::Ok(rc)
500                } else {
501                    FlgError::Unknown(rc)
502                }
503            } else {
504                FlgError::NotInit(rc)
505            }
506        }
507    }
508
509    /// 同时翻转多个事件标志位
510    ///
511    /// + 此CAPI会将事件标志位图中,被掩码 `msk` 覆盖的位全部翻转,
512    ///   然后 **广播** 所有正在等待的线程。
513    /// + 线程唤醒后通过比对位图状态,确定事件是否已经满足触发条件,
514    ///   若满足触发条件,就退出等待;若未满足触发条件,重新进入阻塞等待状态。
515    ///
516    /// # 参数说明
517    ///
518    /// + msk: 事件的位图掩码
519    pub fn x1m(&self, msk: &Bmp<N>) -> FlgError {
520        unsafe {
521            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
522            if rc == 0 {
523                rc = xwrustffi_flg_x1m(self.flg.get() as _, msk.bmp.get() as _);
524                xwrustffi_flg_put(self.flg.get() as _);
525                if XWOK == rc {
526                    FlgError::Ok(rc)
527                } else {
528                    FlgError::Unknown(rc)
529                }
530            } else {
531                FlgError::NotInit(rc)
532            }
533        }
534    }
535
536    /// 翻转单个事件标志位
537    ///
538    /// + 此CAPI会将事件标志位图中,序号为 `pos` 的单个位翻转,
539    ///   然后 **广播** 所有正在等待的线程。
540    /// + 线程唤醒后通过比对位图状态,确定事件是否已经满足触发条件,
541    ///   若满足触发条件,就退出等待;若未满足触发条件,重新进入阻塞等待状态。
542    ///
543    /// # 参数说明
544    ///
545    /// + pos: 事件的序号
546    pub fn x1i(&self, pos: XwSq) -> FlgError {
547        unsafe {
548            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
549            if rc == 0 {
550                rc = xwrustffi_flg_x1i(self.flg.get() as _, pos);
551                xwrustffi_flg_put(self.flg.get() as _);
552                if XWOK == rc {
553                    FlgError::Ok(rc)
554                } else {
555                    FlgError::Unknown(rc)
556                }
557            } else {
558                FlgError::NotInit(rc)
559            }
560        }
561    }
562
563    /// 等待事件
564    ///
565    /// + 当没有检测到事件时,线程会阻塞等待。
566    /// + 当检测到事件时,线程被唤醒,然后返回 [`FlgError::Ok`] 。
567    /// + 当线程阻塞等待被中断时,返回 [`FlgError::Interrupt`] 。
568    ///
569    /// # 事件的触发条件
570    ///
571    /// 事件的触发条件可通过参数 `tg` 设置。事件的触发条件分为两类。
572    ///
573    /// ## 电平触发
574    ///
575    /// **电平触发** 源于数字电路,是一种类比概念,是指事件位图的特定状态( **1** 或 **0** )所产生的触发事件,包括:
576    ///
577    /// + [`Trigger::SetAll`] 所有事件位被置 **1** 触发
578    /// + [`Trigger::SetAny`] 任意事件位被置 **1** 触发
579    /// + [`Trigger::ClearAll`] 所有事件位被清 **0** 触发
580    /// + [`Trigger::ClearAny`] 任意事件位被清 **0** 触发
581    ///
582    /// **电平触发** 时,若参数 `consumption` 取值 `true` ,表示线程在读取事件位图后,会 **清除** 事件位图。
583    /// **电平触发** 时,参数 `origin` 返回事件触发 **之后** ,上述 **清除之前** 的位图状态。
584    ///
585    /// ## 边沿触发
586    ///
587    /// **边沿触发** 源于数字电路,是一种类比概念,是指事件状态发生改变( **1** 变 **0** 或 **0** 变 **1** )时产生的唤醒信号,包括:
588    ///
589    /// + [`Trigger::SetAll`] 所有事件位发生翻转触发
590    /// + [`Trigger::SetAny`] 任意事件位发生翻转触发
591    ///
592    /// **边沿触发** 时,参数 `consumption` 没有意义。
593    /// **边沿触发** 时,必须要有一个初始状态,就像数字电路一样:
594    ///
595    /// + 当位的初始值为 **0** (低电平),然后跳变到 **1** (高电平)的瞬间被称为上升沿。此时触发的事件被称为上升沿触发。
596    /// + 当位的初始值为 **1** (高电平),然后跳变到 **0** (低电平)的瞬间被称为下降沿。此时触发的事件被称为下降沿触发。
597    ///
598    /// 初始值就由参数 `origin` 指明,触发后,事件位发生跳变,跳变后的结果还是由参数 `origin` 返回。
599    ///
600    /// # 参数说明
601    ///
602    /// + tg: 事件触发条件
603    ///   + **电平触发**
604    ///     + [`Trigger::SetAll`] 所有事件位被置 **1** 触发
605    ///     + [`Trigger::SetAny`] 任意事件位被置 **1** 触发
606    ///     + [`Trigger::ClearAll`] 所有事件位被清 **0** 触发
607    ///     + [`Trigger::ClearAny`] 任意事件位被清 **0** 触发
608    ///   + **边沿触发**
609    ///     + [`Trigger::SetAll`] 所有事件位发生翻转触发
610    ///     + [`Trigger::SetAny`] 任意事件位发生翻转触发
611    /// + consumption: 事件触发后是否清除事件
612    /// + origin: 事件位图
613    ///   + **电平触发** 时,参数 `origin` 用于返回事件 **触发之后** ,**清除之前** 的位图状态。
614    ///     “**清除之前**” 是指 `consumption` 为 `true` 时,自动清除事件标志之前。
615    ///   + **边沿触发** 时
616    ///     + 输入时 `origin` 指明事件标志位图的初始值,用于评估事件位图是否发生变化。
617    ///     + 输出时 `origin` 返回触发后的事件标志位图状态(可作为下一次调用的初始值)。
618    /// + msk: 事件的位图掩码,表示只关注掩码部分的事件
619    ///
620    /// # 上下文
621    ///
622    /// + 线程
623    ///
624    /// # 错误码
625    ///
626    /// + [`FlgError::Ok`] 没有错误
627    /// + [`FlgError::NotInit`] 事件标志没有初始化
628    /// + [`FlgError::Interrupt`] 等待被中断
629    /// + [`FlgError::NotThreadContext`] 不在线程上下文内
630    ///
631    /// # 示例
632    ///
633    /// ```rust
634    /// extern crate alloc;
635    /// use alloc::sync::Arc;
636    ///
637    /// use xwrust::xwos::sync::flg::*;
638    ///
639    /// pub fn xwrust_example_flg() {
640    /// }
641    /// ```
642    pub fn wait(&self, tg: Trigger, consumption: bool,
643                origin: &mut Bmp<N>, msk: &Bmp<N>) -> FlgError {
644        unsafe {
645            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
646            if rc == 0 {
647                rc = xwrustffi_flg_wait(self.flg.get() as _, tg as XwSq, consumption,
648                                        origin.bmp.get() as _, msk.bmp.get() as _);
649                xwrustffi_flg_put(self.flg.get() as _);
650                if XWOK == rc {
651                    FlgError::Ok(rc)
652                } else if -EINTR == rc {
653                    FlgError::Interrupt(rc)
654                } else if -ENOTTHDCTX == rc {
655                    FlgError::NotThreadContext(rc)
656                } else {
657                    FlgError::Unknown(rc)
658                }
659            } else {
660                FlgError::NotInit(rc)
661            }
662        }
663    }
664
665    /// 限时等待事件
666    ///
667    /// + 当没有检测到事件时,线程会阻塞等待,等待时会指定一个唤醒时间点 `to` 。
668    /// + 当检测到事件时,线程被唤醒,然后返回 [`FlgError::Ok`] 。
669    /// + 当线程阻塞等待被中断时,返回 [`FlgError::Interrupt`] 。
670    /// + 当到达指定的唤醒时间点时,线程被唤醒,并返回 [`FlgError::Timedout`] 。
671    ///
672    /// # 事件的触发条件
673    ///
674    /// 事件的触发条件可通过参数 `tg` 设置。事件的触发条件分为两类。
675    ///
676    /// ## 电平触发
677    ///
678    /// **电平触发** 源于数字电路,是一种类比概念,是指事件位图的特定状态( **1** 或 **0** )所产生的触发事件,包括:
679    ///
680    /// + [`Trigger::SetAll`] 所有事件位被置 **1** 触发
681    /// + [`Trigger::SetAny`] 任意事件位被置 **1** 触发
682    /// + [`Trigger::ClearAll`] 所有事件位被清 **0** 触发
683    /// + [`Trigger::ClearAny`] 任意事件位被清 **0** 触发
684    ///
685    /// **电平触发** 时,若参数 `consumption` 取值 `true` ,表示线程在读取事件位图后,会 **清除** 事件位图。
686    /// **电平触发** 时,参数 `origin` 返回事件触发 **之后** ,上述 **清除之前** 的位图状态。
687    ///
688    /// ## 边沿触发
689    ///
690    /// **边沿触发** 源于数字电路,是一种类比概念,是指事件状态发生改变( **1** 变 **0** 或 **0** 变 **1** )时产生的唤醒信号,包括:
691    ///
692    /// + [`Trigger::SetAll`] 所有事件位发生翻转触发
693    /// + [`Trigger::SetAny`] 任意事件位发生翻转触发
694    ///
695    /// **边沿触发** 时,参数 `consumption` 没有意义。
696    /// **边沿触发** 时,必须要有一个初始状态,就像数字电路一样:
697    ///
698    /// + 当位的初始值为 **0** (低电平),然后跳变到 **1** (高电平)的瞬间被称为上升沿。此时触发的事件被称为上升沿触发。
699    /// + 当位的初始值为 **1** (高电平),然后跳变到 **0** (低电平)的瞬间被称为下降沿。此时触发的事件被称为下降沿触发。
700    ///
701    /// 初始值就由参数 `origin` 指明,触发后,事件位发生跳变,跳变后的结果还是由参数 `origin` 返回。
702    ///
703    /// # 参数说明
704    ///
705    /// + tg: 事件触发条件
706    ///   + **电平触发**
707    ///     + [`Trigger::SetAll`] 所有事件位被置 **1** 触发
708    ///     + [`Trigger::SetAny`] 任意事件位被置 **1** 触发
709    ///     + [`Trigger::ClearAll`] 所有事件位被清 **0** 触发
710    ///     + [`Trigger::ClearAny`] 任意事件位被清 **0** 触发
711    ///   + **边沿触发**
712    ///     + [`Trigger::SetAll`] 所有事件位发生翻转触发
713    ///     + [`Trigger::SetAny`] 任意事件位发生翻转触发
714    /// + consumption: 事件触发后是否清除事件
715    /// + origin: 事件位图
716    ///   + **电平触发** 时,参数 `origin` 用于返回事件 **触发之后** ,**清除之前** 的位图状态。
717    ///     “**清除之前**” 是指 `consumption` 为 `true` 时,自动清除事件标志之前。
718    ///   + **边沿触发** 时
719    ///     + 输入时 `origin` 指明事件标志位图的初始值,用于评估事件位图是否发生变化。
720    ///     + 输出时 `origin` 返回触发后的事件标志位图状态(可作为下一次调用的初始值)。
721    /// + msk: 事件的位图掩码,表示只关注掩码部分的事件
722    ///
723    /// # 上下文
724    ///
725    /// + 线程
726    ///
727    /// # 错误码
728    ///
729    /// + [`FlgError::Ok`] 没有错误
730    /// + [`FlgError::NotInit`] 事件标志没有初始化
731    /// + [`FlgError::Interrupt`] 等待被中断
732    /// + [`FlgError::Timedout`] 等待超时
733    /// + [`FlgError::NotThreadContext`] 不在线程上下文内
734    ///
735    /// # 示例
736    ///
737    /// ```rust
738    /// extern crate alloc;
739    /// use alloc::sync::Arc;
740    ///
741    /// use xwrust::xwos::sync::flg::*;
742    ///
743    /// pub fn xwrust_example_flg() {
744    /// }
745    /// ```
746    pub fn wait_to(&self, tg: Trigger, consumption: bool,
747                   origin: &mut Bmp<N>, msk: &Bmp<N>, to: XwTm) -> FlgError {
748        unsafe {
749            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
750            if rc == 0 {
751                rc = xwrustffi_flg_wait_to(self.flg.get() as _, tg as XwSq, consumption,
752                                           origin.bmp.get() as _, msk.bmp.get() as _, to);
753                xwrustffi_flg_put(self.flg.get() as _);
754                if XWOK == rc {
755                    FlgError::Ok(rc)
756                } else if -EINTR == rc {
757                    FlgError::Interrupt(rc)
758                } else if -ETIMEDOUT == rc {
759                    FlgError::Timedout(rc)
760                } else if -ENOTTHDCTX == rc {
761                    FlgError::NotThreadContext(rc)
762                } else {
763                    FlgError::Unknown(rc)
764                }
765            } else {
766                FlgError::NotInit(rc)
767            }
768        }
769    }
770
771    /// 检查事件
772    ///
773    /// + 当检测到事件时,立即返回 [`FlgError::Ok`] 。
774    /// + 当没有检测到事件时,立即返回 [`FlgError::NoEvent`] 。
775    ///
776    /// # 事件的触发条件
777    ///
778    /// 事件的触发条件可通过参数 `tg` 设置。事件的触发条件分为两类。
779    ///
780    /// ## 电平触发
781    ///
782    /// **电平触发** 源于数字电路,是一种类比概念,是指事件位图的特定状态( **1** 或 **0** )所产生的触发事件,包括:
783    ///
784    /// + [`Trigger::SetAll`] 所有事件位被置 **1** 触发
785    /// + [`Trigger::SetAny`] 任意事件位被置 **1** 触发
786    /// + [`Trigger::ClearAll`] 所有事件位被清 **0** 触发
787    /// + [`Trigger::ClearAny`] 任意事件位被清 **0** 触发
788    ///
789    /// **电平触发** 时,若参数 `consumption` 取值 `true` ,表示线程在读取事件位图后,会 **清除** 事件位图。
790    /// **电平触发** 时,参数 `origin` 返回事件触发 **之后** ,上述 **清除之前** 的位图状态。
791    ///
792    /// ## 边沿触发
793    ///
794    /// **边沿触发** 源于数字电路,是一种类比概念,是指事件状态发生改变( **1** 变 **0** 或 **0** 变 **1** )时产生的唤醒信号,包括:
795    ///
796    /// + [`Trigger::SetAll`] 所有事件位发生翻转触发
797    /// + [`Trigger::SetAny`] 任意事件位发生翻转触发
798    ///
799    /// **边沿触发** 时,参数 `consumption` 没有意义。
800    /// **边沿触发** 时,必须要有一个初始状态,就像数字电路一样:
801    ///
802    /// + 当位的初始值为 **0** (低电平),然后跳变到 **1** (高电平)的瞬间被称为上升沿。此时触发的事件被称为上升沿触发。
803    /// + 当位的初始值为 **1** (高电平),然后跳变到 **0** (低电平)的瞬间被称为下降沿。此时触发的事件被称为下降沿触发。
804    ///
805    /// 初始值就由参数 `origin` 指明,触发后,事件位发生跳变,跳变后的结果还是由参数 `origin` 返回。
806    ///
807    /// # 参数说明
808    ///
809    /// + tg: 事件触发条件
810    ///   + **电平触发**
811    ///     + [`Trigger::SetAll`] 所有事件位被置 **1** 触发
812    ///     + [`Trigger::SetAny`] 任意事件位被置 **1** 触发
813    ///     + [`Trigger::ClearAll`] 所有事件位被清 **0** 触发
814    ///     + [`Trigger::ClearAny`] 任意事件位被清 **0** 触发
815    ///   + **边沿触发**
816    ///     + [`Trigger::SetAll`] 所有事件位发生翻转触发
817    ///     + [`Trigger::SetAny`] 任意事件位发生翻转触发
818    /// + consumption: 事件触发后是否清除事件
819    /// + origin: 事件位图
820    ///   + **电平触发** 时,参数 `origin` 用于返回事件 **触发之后** ,**清除之前** 的位图状态。
821    ///     “**清除之前**” 是指 `consumption` 为 `true` 时,自动清除事件标志之前。
822    ///   + **边沿触发** 时
823    ///     + 输入时 `origin` 指明事件标志位图的初始值,用于评估事件位图是否发生变化。
824    ///     + 输出时 `origin` 返回触发后的事件标志位图状态(可作为下一次调用的初始值)。
825    /// + msk: 事件的位图掩码,表示只关注掩码部分的事件
826    ///
827    /// # 上下文
828    ///
829    /// + 任意
830    ///
831    /// # 错误码
832    ///
833    /// + [`FlgError::Ok`] 没有错误
834    /// + [`FlgError::NotInit`] 事件标志没有初始化
835    /// + [`FlgError::NoEvent`] 没有检测到事件
836    ///
837    /// # 示例
838    ///
839    /// ```rust
840    /// extern crate alloc;
841    /// use alloc::sync::Arc;
842    ///
843    /// use xwrust::xwos::sync::flg::*;
844    ///
845    /// pub fn xwrust_example_flg() {
846    /// }
847    /// ```
848    pub fn trywait(&self, tg: Trigger, consumption: bool,
849                   origin: &mut Bmp<N>, msk: &Bmp<N>) -> FlgError {
850        unsafe {
851            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
852            if rc == 0 {
853                rc = xwrustffi_flg_trywait(self.flg.get() as _, tg as XwSq, consumption,
854                                           origin.bmp.get() as _, msk.bmp.get() as _);
855                xwrustffi_flg_put(self.flg.get() as _);
856                if XWOK == rc {
857                    FlgError::Ok(rc)
858                } else if -ENODATA == rc {
859                    FlgError::NoEvent(rc)
860                } else {
861                    FlgError::Unknown(rc)
862                }
863            } else {
864                FlgError::NotInit(rc)
865            }
866        }
867    }
868
869    /// 等待事件,且等待不可被中断
870    ///
871    /// + 当没有检测到事件时,线程会阻塞等待。
872    /// + 当检测到事件时,线程被唤醒,然后返回 [`FlgError::Ok`] 。
873    /// + 当线程阻塞等待被中断时,返回 [`FlgError::Interrupt`] 。
874    ///
875    /// # 事件的触发条件
876    ///
877    /// 事件的触发条件可通过参数 `tg` 设置。事件的触发条件分为两类。
878    ///
879    /// ## 电平触发
880    ///
881    /// **电平触发** 源于数字电路,是一种类比概念,是指事件位图的特定状态( **1** 或 **0** )所产生的触发事件,包括:
882    ///
883    /// + [`Trigger::SetAll`] 所有事件位被置 **1** 触发
884    /// + [`Trigger::SetAny`] 任意事件位被置 **1** 触发
885    /// + [`Trigger::ClearAll`] 所有事件位被清 **0** 触发
886    /// + [`Trigger::ClearAny`] 任意事件位被清 **0** 触发
887    ///
888    /// **电平触发** 时,若参数 `consumption` 取值 `true` ,表示线程在读取事件位图后,会 **清除** 事件位图。
889    /// **电平触发** 时,参数 `origin` 返回事件触发 **之后** ,上述 **清除之前** 的位图状态。
890    ///
891    /// ## 边沿触发
892    ///
893    /// **边沿触发** 源于数字电路,是一种类比概念,是指事件状态发生改变( **1** 变 **0** 或 **0** 变 **1** )时产生的唤醒信号,包括:
894    ///
895    /// + [`Trigger::SetAll`] 所有事件位发生翻转触发
896    /// + [`Trigger::SetAny`] 任意事件位发生翻转触发
897    ///
898    /// **边沿触发** 时,参数 `consumption` 没有意义。
899    /// **边沿触发** 时,必须要有一个初始状态,就像数字电路一样:
900    ///
901    /// + 当位的初始值为 **0** (低电平),然后跳变到 **1** (高电平)的瞬间被称为上升沿。此时触发的事件被称为上升沿触发。
902    /// + 当位的初始值为 **1** (高电平),然后跳变到 **0** (低电平)的瞬间被称为下降沿。此时触发的事件被称为下降沿触发。
903    ///
904    /// 初始值就由参数 `origin` 指明,触发后,事件位发生跳变,跳变后的结果还是由参数 `origin` 返回。
905    ///
906    /// # 参数说明
907    ///
908    /// + tg: 事件触发条件
909    ///   + **电平触发**
910    ///     + [`Trigger::SetAll`] 所有事件位被置 **1** 触发
911    ///     + [`Trigger::SetAny`] 任意事件位被置 **1** 触发
912    ///     + [`Trigger::ClearAll`] 所有事件位被清 **0** 触发
913    ///     + [`Trigger::ClearAny`] 任意事件位被清 **0** 触发
914    ///   + **边沿触发**
915    ///     + [`Trigger::SetAll`] 所有事件位发生翻转触发
916    ///     + [`Trigger::SetAny`] 任意事件位发生翻转触发
917    /// + consumption: 事件触发后是否清除事件
918    /// + origin: 事件位图
919    ///   + **电平触发** 时,参数 `origin` 用于返回事件 **触发之后** ,**清除之前** 的位图状态。
920    ///     “**清除之前**” 是指 `consumption` 为 `true` 时,自动清除事件标志之前。
921    ///   + **边沿触发** 时
922    ///     + 输入时 `origin` 指明事件标志位图的初始值,用于评估事件位图是否发生变化。
923    ///     + 输出时 `origin` 返回触发后的事件标志位图状态(可作为下一次调用的初始值)。
924    /// + msk: 事件的位图掩码,表示只关注掩码部分的事件
925    ///
926    /// # 上下文
927    ///
928    /// + 线程
929    ///
930    /// # 错误码
931    ///
932    /// + [`FlgError::Ok`] 没有错误
933    /// + [`FlgError::NotInit`] 事件标志没有初始化
934    /// + [`FlgError::Interrupt`] 等待被中断
935    /// + [`FlgError::NotThreadContext`] 不在线程上下文内
936    ///
937    /// # 示例
938    ///
939    /// ```rust
940    /// extern crate alloc;
941    /// use alloc::sync::Arc;
942    ///
943    /// use xwrust::xwos::sync::flg::*;
944    ///
945    /// pub fn xwrust_example_flg() {
946    /// }
947    /// ```
948    pub fn wait_unintr(&self, tg: Trigger, consumption: bool,
949                       origin: &mut Bmp<N>, msk: &Bmp<N>) -> FlgError {
950        unsafe {
951            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
952            if rc == 0 {
953                rc = xwrustffi_flg_wait_unintr(self.flg.get() as _, tg as XwSq, consumption,
954                                               origin.bmp.get() as _, msk.bmp.get() as _);
955                xwrustffi_flg_put(self.flg.get() as _);
956                if XWOK == rc {
957                    FlgError::Ok(rc)
958                } else if -EINTR == rc {
959                    FlgError::Interrupt(rc)
960                } else if -ENOTTHDCTX == rc {
961                    FlgError::NotThreadContext(rc)
962                } else {
963                    FlgError::Unknown(rc)
964                }
965            } else {
966                FlgError::NotInit(rc)
967            }
968        }
969    }
970
971    /// 绑定事件标志对象到信号选择器
972    ///
973    /// + 事件标志绑定到信号选择器上时,采用 **非独占** 的方式进行绑定。
974    /// + 绑定成功,通过 [`Ok()`] 返回 [`FlgSel<'a, N, M>`] 。
975    /// + 如果位置已被其他 **同步对象** 以 **独占** 的方式占领,通过 [`Err()`] 返回 [`FlgError::SelPosBusy`] 。
976    /// + 当指定的位置超出范围(例如 [`Sel<M>`] 只有8个位置,用户偏偏要绑定到位置9 ),通过 [`Err()`] 返回 [`FlgError::OutOfSelPos`] 。
977    /// + 重复绑定,通过 [`Err()`] 返回 [`FlgError::AlreadyBound`] 。
978    ///
979    /// [`FlgSel<'a, N, M>`] 中包含事件标志的绑定信息。 [`FlgSel<'a, N, M>`] 与 [`Flg<N>`] 与 [`Sel<M>`] 具有相同的生命周期约束 `'a` 。
980    /// [`FlgSel::selected()`] 可用来判断事件标志是否被选择。当 [`FlgSel<'a, N, M>`] [`drop()`] 时,会自动解绑。
981    ///
982    /// # 参数说明
983    ///
984    /// + sel: 信号选择器的引用
985    /// + pos: 位置
986    ///
987    /// # 上下文
988    ///
989    /// + 任意
990    ///
991    /// # 错误码
992    ///
993    /// + [`FlgError::OutOfSelPos`] 信号选择器的位置超出范围
994    /// + [`FlgError::AlreadyBound`] 事件标志已经绑定
995    /// + [`FlgError::SelPosBusy`] 信号选择器的位置被占用
996    ///
997    /// # 示例
998    ///
999    /// ```rust
1000    /// pub fn xwrust_example_sel() {
1001    ///     // ...省略...
1002    ///     let flg0 = Arc::new(Flg::new());
1003    ///     flg0.init();
1004    ///     let flg0sel = match flg0.bind(&sel, 0) {
1005    ///         Ok(s) => { // 绑定成功,`s` 为 `FlgSel`
1006    ///             s
1007    ///         },
1008    ///         Err(e) => { // 绑定失败,`e` 为 `SelError`
1009    ///             return;
1010    ///         }
1011    ///     };
1012    ///     // ...省略...
1013    /// }
1014    /// ```
1015    ///
1016    /// [`FlgSel<'a, N, M>`]: FlgSel
1017    /// [`Ok()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Ok>
1018    /// [`Err()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
1019    /// [`Sel<M>`]: super::sel::Sel
1020    /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
1021    pub fn bind<'a, const M: XwSz>(&'a self, sel: &'a Sel<M>, pos: XwSq) ->
1022                                   Result<FlgSel<'a, N, M>, FlgError>
1023    where
1024        [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
1025    {
1026        unsafe {
1027            let mut rc = xwrustffi_flg_acquire(self.flg.get() as _, *self.tik.get());
1028            if rc == 0 {
1029                rc = xwrustffi_flg_bind(self.flg.get() as _, sel.sel.get() as _, pos);
1030                if XWOK == rc {
1031                    Ok(FlgSel {
1032                        flg: self,
1033                        sel: sel,
1034                        pos: pos,
1035                    })
1036                } else if -ECHRNG == rc {
1037                    Err(FlgError::OutOfSelPos(rc))
1038                } else if -EALREADY == rc {
1039                    Err(FlgError::AlreadyBound(rc))
1040                } else if -EBUSY == rc {
1041                    Err(FlgError::SelPosBusy(rc))
1042                } else {
1043                    Err(FlgError::Unknown(rc))
1044                }
1045            } else {
1046                Err(FlgError::NotInit(rc))
1047            }
1048        }
1049    }
1050}
1051
1052/// 事件标志的选择子
1053///
1054/// `FlgSel<'a, N, M>` 与 [`Flg<N>`] 与 [`Sel<M>`] 具有相同的生命周期约束 `'a` 。因为 `FlgSel<'a, N, M>` 中包含了 [`Flg<N>`] 与 [`Sel<M>`] 的引用。
1055///
1056/// `FlgSel<'a, N, M>` 中包含了绑定的位置信息,事件标志采用 **非独占** 的方式进行绑定。
1057///
1058/// [`FlgSel::selected()`] 可用来判断事件标志是否被选择。
1059///
1060/// 当 `FlgSel<'a, N, M>` 被 [`drop()`] 时,会自动将 [`Flg<N>`] 从 [`Sel<M>`] 解绑。
1061///
1062/// [`Sel<M>`]: super::sel::Sel
1063/// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
1064pub struct FlgSel<'a, const N: XwSz, const M: XwSz>
1065where
1066    [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
1067    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
1068{
1069    /// 事件标志
1070    pub flg: &'a Flg<N>,
1071    /// 信号选择器
1072    pub sel: &'a Sel<M>,
1073    /// 位置
1074    pub pos: XwSq,
1075}
1076
1077unsafe impl<'a, const N: XwSz, const M: XwSz> Send for FlgSel<'a, N, M>
1078where
1079    [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
1080    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
1081{}
1082
1083unsafe impl<'a, const N: XwSz, const M: XwSz> Sync for FlgSel<'a, N, M>
1084where
1085    [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
1086    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
1087{}
1088
1089impl<'a, const N: XwSz, const M: XwSz> Drop for FlgSel<'a, N, M>
1090where
1091    [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
1092    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
1093{
1094    fn drop(&mut self) {
1095        unsafe {
1096            xwrustffi_flg_unbind(self.flg.flg.get() as _, self.flg.flg.get() as _);
1097            xwrustffi_flg_put(self.flg.flg.get() as _);
1098        }
1099    }
1100}
1101
1102impl<'a, const N: XwSz, const M: XwSz> FlgSel<'a, N, M>
1103where
1104    [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
1105    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
1106{
1107    /// 判断触发的 **选择信号** 是否包括此事件标志
1108    ///
1109    /// # 示例
1110    ///
1111    /// ```rust
1112    ///     let msk = Bmp::<8>::new(); // 8位位图
1113    ///     msk.s1all(); // 掩码为0xFF
1114    ///     loop {
1115    ///         let res = sel.select(&msk);
1116    ///         match res {
1117    ///             Ok(t) => { // 信号选择器上有 **选择信号** , `t` 为 **选择信号** 的位图。
1118    ///                 if flg0sel.selected(&t) { // 事件标志被选择到
1119    ///                 }
1120    ///             },
1121    ///             Err(e) => { // 等待信号选择器失败,`e` 为 `SelError`
1122    ///                 flgeak;
1123    ///             },
1124    ///         }
1125    ///     }
1126    /// ```
1127    pub fn selected(&self, trg: &Bmp<M>) -> bool {
1128        trg.t1i(self.pos)
1129    }
1130}