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}