xwrust/xwos/sync/sel.rs
1//! XWOS RUST:信号选择器
2//! ========
3//!
4//! 信号选择器使用位图 [`Bmp`] 来管理一组 **同步对象** 。使得单一线程可以同时等待多个 **同步对象** 。
5//!
6//! 每个 **同步对象** 在信号选择器位图中都绑定一个特定的 **位** ,
7//!
8//! 当这些 **同步对象** 发送 **选择信号** 时,信号选择器位图中特定的 **位** 被置 **1** ,同时唤醒正在等待信号选择器的线程。
9//! 线程唤醒后可以通过检测哪些 **位** 被置 **1** 来判断哪些 **同步对象** 发送了 **选择信号** 。
10//!
11//!
12//! # 同步对象的绑定与解绑
13//!
14//! XWOS RUST的所有 **同步对象** 都有一个相似的用于绑定的方法:
15//!
16//! + [`Sem::bind()`]
17//! + [`Cond::bind()`]
18//! + [`Flg::bind()`]
19//! + [`Br::bind()`]
20//! + [`Sel::bind()`]
21//!
22//! 绑定后会返回各个 **同步对象** 的 **选择子** :
23//!
24//! + [`SemSel`]
25//! + [`CondSel`]
26//! + [`FlgSel`]
27//! + [`BrSel`]
28//! + [`SelSel`]
29//!
30//! **选择子** 被 [`drop()`] 时,会自动解绑。
31//!
32//!
33//! **同步对象** 绑定操作又分为 **独占绑定** 与 **非独占绑定** :
34//!
35//! + 独占绑定:是指 **同步对象** 一旦绑定了信号选择器位图中的某一位后,其他 **同步对象** 不可再绑定此位,发送的 **选择信号** 也被称为 **独占** 方式的 **选择信号** ;
36//! + 非独占绑定:是指 **同步对象** 一旦绑定了信号选择器位图中的某一位后,其他 **同步对象** 还可继续再绑定此位,发送的 **选择信号** 也被称为 **非独占** 方式的 **选择信号** 。
37//!
38//!
39//! **同步对象** 采用的绑定方式:
40//!
41//! + 信号量:独占绑定
42//! + 条件量:非独占绑定
43//! + 事件标志:非独占绑定
44//! + 线程栅栏:非独占绑定
45//! + 信号选择器:非独占绑定
46//!
47//!
48//! # 选择信号
49//!
50//! ## 选择信号的设置
51//!
52//! **选择信号** 的设置,对于不同的 **同步对象** 有不同解释:
53//!
54//! + 信号量
55//! + 计数器的值大于 **0** 时就会被设置。
56//! + 条件量
57//! + 广播操作 [`Cond::broadcast`]
58//! + 事件标志
59//! + 事件标志位图中任何一位发生改变的操作:
60//! + [`Flg::s1m`]
61//! + [`Flg::s1i`]
62//! + [`Flg::c0m`]
63//! + [`Flg::c0i`]
64//! + [`Flg::x1m`]
65//! + [`Flg::x1i`]
66//! + 线程栅栏
67//! + 所有线程抵达栅栏,并同时被唤醒;
68//! + 信号选择器
69//! + 信号选择器本身也是 **同步对象** ,也可绑定在另一个信号选择器上。当源信号选择器收到了 **选择信号** ,会将其传递到绑定的另一个目的信号选择器上。
70//!
71//! ## 选择信号的清除
72//!
73//! ### **独占** 方式的 **选择信号**
74//!
75//! + 信号量:当信号量中的计数器的值小于等于 **0** 时, **选择信号** 才会被清除。
76//!
77//! ### **非独占** 方式的 **选择信号**
78//!
79//! **非独占** 方式绑定的 **同步对象** 向信号选择器发送 **选择信号** 后,其位图中的位置会被置 **1** 。
80//! 同时会唤醒所有等待的线程,此时线程们会竞争进入信号选择器的临界区。
81//!
82//! 最先进入的线程会读取信号选择器的 **选择信号** 位图,并与调用函数时传递的 **掩码** 进行比较,判断是否有 **掩码** 中的 **选择信号** :
83//!
84//! + 如果有,会清除信号选择器位图中 **所有** 的 **非独占** 方式的 **选择信号** ,包括 **掩码** 中没有设置的 **选择信号** 。
85//! 因此后续线程将无法再检测到任何 **非独占** 方式的 **选择信号** ,会重新阻塞等待。
86//! XWOS不推荐在信号选择器上,多于1个线程等待。
87//! + 如果没有,线程会重新阻塞等待。然后下一个线程进入临界区检测。
88//!
89//!
90//! # 创建
91//!
92//! XWOS RUST的信号量可使用 [`Sel::new()`] 创建。
93//! 创建时需要指明泛型中的常量 `N` ,表示信号选择器中有个多少个位置可以绑定。
94//!
95//! + 可以创建具有静态生命周期 [`static`] 约束的全局变量:
96//!
97//! ```rust
98//! use xwrust::xwos::sync::sel::*;
99//!
100//! static GLOBAL_SEL: Sel<8> = Sel::new();
101//! ```
102//!
103//! + 也可以使用 [`alloc::sync::Arc`] 在heap中创建:
104//!
105//! ```rust
106//! extern crate alloc;
107//! use alloc::sync::Arc;
108//!
109//! use xwrust::xwos::sync::sel::*;
110//!
111//! pub fn xwrust_example_sel() {
112//! let sel = Arc::new(Sel::<8>::new());
113//! }
114//! ```
115//!
116//!
117//! # 初始化
118//!
119//! 无论以何种方式创建的信号选择器,都必须在使用前调用 [`Sel::init()`] 进行初始化:
120//!
121//! ```rust
122//! pub fn xwrust_example_sel() {
123//! GLOBAL_SEL.init();
124//! sel.init();
125//! }
126//! ```
127//!
128//!
129//! ## 等待信号选择器中的 **选择信号**
130//!
131//! [`Sel::select()`] 可用于等待信号选择器中的 **选择信号** 。
132//!
133//! + 当没有同步对象向信号选择器发送 **选择信号** 时,线程会阻塞等待。
134//! + 当 **任意** 同步对象向信号选择器发送 **选择信号** 时,线程被唤醒,然后返回 [`Bmp<N>`] 。
135//! + 当线程阻塞等待被中断时,返回 [`SelError::Interrupt`] 。
136//!
137//! ## 限时等待信号选择器中的 **选择信号**
138//!
139//! [`Sel::select_to()`] 可用于限时等待信号选择器中的 **选择信号** 。
140//!
141//! + 当没有同步对象向信号选择器发送 **选择信号** 时,线程会阻塞等待,等待时会指定一个唤醒时间点。
142//! + 当 **任意** 同步对象向信号选择器发送 **选择信号** 时,线程被唤醒,然后返回 [`Bmp<N>`] 。
143//! + 当线程阻塞等待被中断时,返回 [`SelError::Interrupt`] 。
144//! + 当到达指定的唤醒时间点,线程被唤醒,并返回 [`SelError::Timedout`] 。
145//!
146//! [`Sel::tryselect()`] 检测信号选择器中是否有 **选择信号** 。
147//!
148//! + 当检测到 **任意** 同步对象向信号选择器发送 **选择信号** 时,立即返回 [`Bmp<N>`] 。
149//! + 当没有同步对象向信号选择器发送 **选择信号** 时,立即返回 [`SelError::NoSignal`] 。
150//!
151//!
152//! # 获取信号选择器中同步对象槽的数量
153//!
154//! 可以通过方法 [`Sel::get_num()`] 获取信号选择器中位置的数量,这个值是在创建信号选择器时通过泛型常量 `N` 指定的。
155//!
156//!
157//! # 绑定到其他信号选择器
158//!
159//! 信号选择器也是 **同步对象**, 可以通过方法 [`Sel::bind()`] 将信号选择器绑定到另一个信号选择器上,由此可将 **选择信号** 进行传递。
160//!
161//! 信号选择器采用 **非独占** 的方式进行绑定。
162//!
163//!
164//! # 示例
165//!
166//! [XWOS/xwam/xwrust-example/xwrust_example_sel](https://gitee.com/xwos/XWOS/blob/main/xwam/xwrust-example/xwrust_example_sel/src/lib.rs)
167//!
168//!
169//! [`Bmp`]: crate::xwbmp::Bmp
170//! [`Sem::post()`]: super::sem::Sem::post
171//! [`Cond::broadcast`]: super::cond::Cond::broadcast
172//! [`Flg::s1m`]: super::flg::Flg::s1m
173//! [`Flg::s1i`]: super::flg::Flg::s1i
174//! [`Flg::c0m`]: super::flg::Flg::c0m
175//! [`Flg::c0i`]: super::flg::Flg::c0i
176//! [`Flg::x1m`]: super::flg::Flg::x1m
177//! [`Flg::x1i`]: super::flg::Flg::x1i
178//! [`static`]: <https://doc.rust-lang.org/std/keyword.static.html>
179//! [`alloc::sync::Arc`]: <https://doc.rust-lang.org/alloc/sync/struct.Arc.html>
180//! [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
181//! [`Sem::bind()`]: super::sem::Sem::bind
182//! [`Cond::bind()`]: super::cond::Cond::bind
183//! [`Flg::bind()`]: super::flg::Flg::bind
184//! [`Br::bind()`]: super::br::Br::bind
185//! [`SemSel`]: super::sem::SemSel
186//! [`CondSel`]: super::cond::CondSel
187//! [`FlgSel`]: super::flg::FlgSel
188//! [`BrSel`]: super::br::BrSel
189
190extern crate core;
191use core::ffi::*;
192use core::cell::UnsafeCell;
193use core::result::Result;
194
195use crate::types::*;
196use crate::errno::*;
197use crate::xwbmp::*;
198
199
200extern "C" {
201 pub(crate) fn xwrustffi_sel_init(sel: *mut c_void, num: XwSz, bmp: *mut XwBmp, msk: *mut XwBmp) -> XwEr;
202 pub(crate) fn xwrustffi_sel_fini(sel: *mut c_void) -> XwEr;
203 pub(crate) fn xwrustffi_sel_grab(sel: *mut c_void) -> XwEr;
204 pub(crate) fn xwrustffi_sel_put(sel: *mut c_void) -> XwEr;
205 pub(crate) fn xwrustffi_sel_get_tik(sel: *mut c_void) -> XwSq;
206 pub(crate) fn xwrustffi_sel_acquire(sel: *mut c_void, tik: XwSq) -> XwEr;
207 pub(crate) fn xwrustffi_sel_release(sel: *mut c_void, tik: XwSq) -> XwEr;
208 pub(crate) fn xwrustffi_sel_bind(src: *mut c_void, dst: *mut c_void, pos: XwSq) -> XwEr;
209 pub(crate) fn xwrustffi_sel_unbind(src: *mut c_void, dst: *mut c_void) -> XwEr;
210 pub(crate) fn xwrustffi_sel_select(sel: *mut c_void, msk: *mut XwBmp, trg: *mut XwBmp) -> XwEr;
211 pub(crate) fn xwrustffi_sel_select_to(sel: *mut c_void, msk: *mut XwBmp, trg: *mut XwBmp, to: XwTm) -> XwEr;
212 pub(crate) fn xwrustffi_sel_tryselect(sel: *mut c_void, msk: *mut XwBmp, trg: *mut XwBmp) -> XwEr;
213}
214
215/// 信号选择器的错误码
216#[derive(Debug)]
217pub enum SelError {
218 /// 没有错误
219 Ok(XwEr),
220 /// 信号选择器没有初始化
221 NotInit(XwEr),
222 /// 等待被中断
223 Interrupt(XwEr),
224 /// 等待超时
225 Timedout(XwEr),
226 /// 没有检测到 **选择信号**
227 NoSignal(XwEr),
228 /// 不在线程上下文内
229 NotThreadContext(XwEr),
230 /// 信号选择器的位置超出范围
231 OutOfSelPos(XwEr),
232 /// 信号选择器已经绑定
233 AlreadyBound(XwEr),
234 /// 信号选择器的位置被占用
235 SelPosBusy(XwEr),
236 /// 未知错误
237 Unknown(XwEr),
238}
239
240impl SelError {
241 /// 消费掉 `SelError` 自身,返回内部的错误码。
242 pub fn unwrap(self) -> XwEr {
243 match self {
244 Self::Ok(rc) => rc,
245 Self::NotInit(rc) => rc,
246 Self::Interrupt(rc) => rc,
247 Self::Timedout(rc) => rc,
248 Self::NoSignal(rc) => rc,
249 Self::NotThreadContext(rc) => rc,
250 Self::OutOfSelPos(rc) => rc,
251 Self::AlreadyBound(rc) => rc,
252 Self::SelPosBusy(rc) => rc,
253 Self::Unknown(rc) => rc,
254 }
255 }
256
257 /// 如果错误码是 [`SelError::Ok`] ,返回 `true` 。
258 pub const fn is_ok(&self) -> bool {
259 matches!(*self, Self::Ok(_))
260 }
261
262 /// 如果错误码不是 [`SelError::Ok`] ,返回 `true` 。
263 pub const fn is_err(&self) -> bool {
264 !self.is_ok()
265 }
266}
267
268/// XWOS信号选择器对象占用的内存大小
269#[cfg(target_pointer_width = "32")]
270pub const SIZEOF_XWOS_SEL: usize = 64;
271
272/// XWOS信号选择器对象占用的内存大小
273#[cfg(target_pointer_width = "64")]
274pub const SIZEOF_XWOS_SEL: usize = 128;
275
276/// 用于构建信号选择器的内存数组类型
277#[repr(C)]
278#[cfg_attr(target_pointer_width = "32", repr(align(8)))]
279#[cfg_attr(target_pointer_width = "64", repr(align(16)))]
280pub(crate) struct XwosSel<const N: XwSz>
281where
282 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
283{
284 pub(crate) obj: [u8; SIZEOF_XWOS_SEL],
285 pub(crate) bmp: [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
286 pub(crate) msk: [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
287}
288
289/// 信号选择器对象结构体
290pub struct Sel<const N: XwSz>
291where
292 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
293{
294 /// 用于初始化XWOS信号选择器对象的内存空间
295 pub(crate) sel: UnsafeCell<XwosSel<N>>,
296 /// 信号选择器对象的标签
297 pub(crate) tik: UnsafeCell<XwSq>,
298}
299
300unsafe impl<const N: XwSz> Send for Sel<N>
301where
302 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
303{}
304
305unsafe impl<const N: XwSz> Sync for Sel<N>
306where
307 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
308{}
309
310impl<const N: XwSz> Drop for Sel<N>
311where
312 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
313{
314 fn drop(&mut self) {
315 unsafe {
316 xwrustffi_sel_fini(self.sel.get() as _);
317 }
318 }
319}
320
321impl<const N: XwSz> Sel<N>
322where
323 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
324{
325 /// 新建信号选择器对象
326 ///
327 /// 此方法是编译期方法。
328 ///
329 /// # 示例
330 ///
331 /// + 具有 [`static`] 约束的全局变量全局变量:
332 ///
333 /// ```rust
334 /// extern crate alloc;
335 /// use xwrust::xwos::sync::sel::*;
336 ///
337 /// static GLOBAL_SEL: Sel<8> = Sel::new();
338 /// ```
339 ///
340 /// + 在heap中创建:
341 ///
342 /// ```rust
343 /// use alloc::sync::Arc;
344 ///
345 /// pub fn xwrust_example_sel() {
346 /// let sel = Arc::new(Sel::<8>::new());
347 /// }
348 /// ```
349 ///
350 /// [`static`]: https://doc.rust-lang.org/std/keyword.static.html
351 pub const fn new() -> Self {
352 Self {
353 sel: UnsafeCell::new(XwosSel {
354 obj: [0; SIZEOF_XWOS_SEL],
355 bmp: [0; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
356 msk: [0; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
357 }),
358 tik: UnsafeCell::new(0),
359 }
360 }
361
362 /// 初始化信号选择器对象
363 ///
364 /// 信号选择器对象必须调用此方法一次,方可正常使用。
365 ///
366 /// # 上下文
367 ///
368 /// + 任意
369 ///
370 /// # 示例
371 ///
372 /// ```rust
373 /// use xwrust::xwos::sync::sel::*;
374 ///
375 /// static GLOBAL_SEL: Sel<8> = Sel::new();
376 ///
377 /// pub fn xwrust_example_sel() {
378 /// // ...省略...
379 /// GLOBAL_SEL.init();
380 /// // 从此处开始 GLOBAL_SEL 可正常使用
381 /// }
382 /// ```
383 pub fn init(&self) {
384 unsafe {
385 let rc = xwrustffi_sel_acquire(self.sel.get() as _, *self.tik.get());
386 if rc == 0 {
387 xwrustffi_sel_put(self.sel.get() as _);
388 } else {
389 xwrustffi_sel_init(self.sel.get() as _,
390 N,
391 &mut (*self.sel.get()).bmp as _,
392 &mut (*self.sel.get()).msk as _);
393 *self.tik.get() = xwrustffi_sel_get_tik(self.sel.get() as _);
394 }
395 }
396 }
397
398 /// 获取信号选择器中线程槽的数量
399 pub const fn get_num(&self) -> XwSz {
400 N
401 }
402
403 /// 等待信号选择器中的 **选择信号**
404 ///
405 /// + 当没有同步对象向信号选择器发送 **选择信号** 时,线程会阻塞等待。
406 /// + 当 **任意** 同步对象向信号选择器发送 **选择信号** 时,线程被唤醒,然后返回 [`Bmp<N>`] 。
407 /// + 当线程阻塞等待被中断时,返回 [`SelError::Interrupt`] 。
408 ///
409 /// # 参数说明
410 ///
411 /// + msk: 事件的位图掩码
412 ///
413 /// # 上下文
414 ///
415 /// + 线程
416 ///
417 /// # 错误码
418 ///
419 /// + [`SelError::NotInit`] 信号选择器没有初始化
420 /// + [`SelError::Interrupt`] 等待被中断
421 /// + [`SelError::NotThreadContext`] 不在线程上下文内
422 ///
423 /// # 示例
424 ///
425 /// ```rust
426 /// use xwrust::xwbmp::*;
427 /// use xwrust::xwos::sync::sel::*;
428 ///
429 /// pub fn xwrust_example_sel() {
430 /// let sel = Sel::<8>::new();
431 /// sel.init();
432 /// // ...省略bind过程...
433 /// let msk = Bmp::<8>::new();
434 /// msk.s1all(); // 设置掩码
435 /// let res = sel.select(msk);
436 /// match res {
437 /// Ok(t) => { // 等待成功, `t` 为 **选择信号** 的位图
438 /// },
439 /// Err(e) => { // 等待失败, `e` 为 `SelError`
440 /// },
441 /// }
442 /// }
443 /// ```
444 pub fn select(&self, msk: &Bmp<N>) -> Result<Bmp<N>, SelError> {
445 unsafe {
446 let mut rc = xwrustffi_sel_acquire(self.sel.get() as _, *self.tik.get());
447 if rc == 0 {
448 let trg = Bmp::<N>::new();
449 rc = xwrustffi_sel_select(self.sel.get() as _,
450 msk.bmp.get() as _, trg.bmp.get() as _);
451 xwrustffi_sel_put(self.sel.get() as _);
452 if XWOK == rc {
453 Ok(trg)
454 } else if -EINTR == rc {
455 Err(SelError::Interrupt(rc))
456 } else if -ENOTTHDCTX == rc {
457 Err(SelError::NotThreadContext(rc))
458 } else {
459 Err(SelError::Unknown(rc))
460 }
461 } else {
462 Err(SelError::NotInit(rc))
463 }
464 }
465 }
466
467 /// 限时等待所有线程到达栅栏
468 ///
469 /// + 当信号选择器中的线程数量小于指定数量,线程会阻塞等待,等待时会指定一个唤醒时间点。
470 /// + 当信号选择器中的线程数量达到指定数量,线程被唤醒,然后返回 [`Bmp<N>`] 。
471 /// + 当线程阻塞等待被中断时,返回 [`SelError::Interrupt`] 。
472 /// + 当到达指定的唤醒时间点,线程被唤醒,并返回 [`SelError::Timedout`] 。
473 ///
474 /// # 参数说明
475 ///
476 /// + msk: 事件的位图掩码
477 /// + to: 期望唤醒的时间点
478 ///
479 /// # 上下文
480 ///
481 /// + 线程
482 ///
483 /// # 错误码
484 ///
485 /// + [`SelError::NotInit`] 信号选择器没有初始化
486 /// + [`SelError::Interrupt`] 等待被中断
487 /// + [`SelError::Timedout`] 等待超时
488 /// + [`SelError::NotThreadContext`] 不在线程上下文内
489 ///
490 /// # 示例
491 ///
492 /// ```rust
493 /// use xwrust::xwbmp::*;
494 /// use xwrust::xwos::sync::sel::*;
495 ///
496 /// pub fn xwrust_example_sel() {
497 /// let sel = Sel::<8>::new();
498 /// sel.init();
499 /// // ...省略bind过程...
500 /// let msk = Bmp::<8>::new();
501 /// msk.s1all(); // 设置掩码
502 /// let res = sel.select_to(msk, xwtm::ft(xwtm::s(3)));
503 /// match res {
504 /// Ok(t) => { // 等待成功, `t` 为 **选择信号** 的位图
505 /// },
506 /// Err(e) => { // 等待失败, `e` 为 `SelError`
507 /// },
508 /// }
509 /// }
510 /// ```
511 pub fn select_to(&self, msk: &Bmp<N>, to: XwTm) -> Result<Bmp<N>, SelError> {
512 unsafe {
513 let mut rc = xwrustffi_sel_acquire(self.sel.get() as _, *self.tik.get());
514 if rc == 0 {
515 let trg = Bmp::<N>::new();
516 rc = xwrustffi_sel_select_to(self.sel.get() as _,
517 msk.bmp.get() as _, trg.bmp.get() as _,
518 to);
519 xwrustffi_sel_put(self.sel.get() as _);
520 if XWOK == rc {
521 Ok(trg)
522 } else if -EINTR == rc {
523 Err(SelError::Interrupt(rc))
524 } else if -ETIMEDOUT == rc {
525 Err(SelError::Timedout(rc))
526 } else if -ENOTTHDCTX == rc {
527 Err(SelError::NotThreadContext(rc))
528 } else {
529 Err(SelError::Unknown(rc))
530 }
531 } else {
532 Err(SelError::NotInit(rc))
533 }
534 }
535 }
536
537 /// 检测信号选择器中是否有 **选择信号**
538 ///
539 /// + 当检测到 **任意** 同步对象向信号选择器发送 **选择信号** 时,立即返回 [`Bmp<N>`] 。
540 /// + 当没有同步对象向信号选择器发送 **选择信号** 时,立即返回 [`SelError::NoSignal`] 。
541 ///
542 /// # 参数说明
543 ///
544 /// + msk: 事件的位图掩码
545 ///
546 /// # 上下文
547 ///
548 /// + 线程
549 ///
550 /// # 错误码
551 ///
552 /// + [`SelError::NotInit`] 信号选择器没有初始化
553 /// + [`SelError::NoSignal`] 没有检测到 **选择信号**
554 ///
555 /// # 示例
556 ///
557 /// ```rust
558 /// use xwrust::xwbmp::*;
559 /// use xwrust::xwos::sync::sel::*;
560 ///
561 /// pub fn xwrust_example_sel() {
562 /// let sel = Sel::<8>::new();
563 /// sel.init();
564 /// // ...省略bind过程...
565 /// let msk = Bmp::<8>::new();
566 /// msk.s1all(); // 设置掩码
567 /// let res = sel.tryselect(msk);
568 /// match res {
569 /// Ok(t) => { // 等待成功, `t` 为 **选择信号** 的位图
570 /// },
571 /// Err(e) => { // 等待失败, `e` 为 `SelError`
572 /// },
573 /// }
574 /// }
575 /// ```
576 pub fn tryselect(&self, msk: &Bmp<N>) -> Result<Bmp<N>, SelError> {
577 unsafe {
578 let mut rc = xwrustffi_sel_acquire(self.sel.get() as _, *self.tik.get());
579 if rc == 0 {
580 let trg = Bmp::<N>::new();
581 rc = xwrustffi_sel_tryselect(self.sel.get() as _,
582 msk.bmp.get() as _, trg.bmp.get() as _);
583 xwrustffi_sel_put(self.sel.get() as _);
584 if XWOK == rc {
585 Ok(trg)
586 } else if -EINTR == rc {
587 Err(SelError::Interrupt(rc))
588 } else if -ENODATA == rc {
589 Err(SelError::NoSignal(rc))
590 } else {
591 Err(SelError::Unknown(rc))
592 }
593 } else {
594 Err(SelError::NotInit(rc))
595 }
596 }
597 }
598
599 /// 绑定源信号选择器 `src` 到目的信号选择器 `dst`
600 ///
601 /// + 源信号选择器 `src` 绑定到目的信号选择器 `dst` 上时, 采用 **非独占** 的方式进行绑定。
602 /// + 绑定成功,通过 [`Ok()`] 返回 [`SelSel<'a, N, M>`] 。
603 /// + 如果位置已被其他 **同步对象** 以 **独占** 的方式占领,通过 [`Err()`] 返回 [`SelError::SelPosBusy`] 。
604 /// + 当指定的位置超出范围(例如 `dst` 只有8个位置,用户偏偏要绑定到位置9 ),通过 [`Err()`] 返回 [`SelError::OutOfSelPos`] 。
605 /// + 重复绑定,通过 [`Err()`] 返回 [`SelError::AlreadyBound`] 。
606 ///
607 /// [`SelSel<'a, N, M>`] 中包含绑定信息。 [`SelSel<'a, N, M>`] 与 `src` 与 `dst` 具有相同的生命周期约束 `'a` 。
608 /// [`SelSel::selected()`] 可用来判断 `src` 是否被选择。当 [`SelSel<'a, N, M>`] [`drop()`] 时,会自动将 `src` 从 `dst` 解绑。
609 ///
610 /// # 参数说明
611 ///
612 /// + dst: 目的信号选择器的引用
613 /// + pos: 位置
614 ///
615 /// # 上下文
616 ///
617 /// + 任意
618 ///
619 /// # 错误码
620 ///
621 /// + [`SelError::OutOfSelPos`] 信号选择器的位置超出范围
622 /// + [`SelError::AlreadyBound`] 信号选择器已经绑定
623 /// + [`SelError::SelPosBusy`] 信号选择器的位置被占用
624 ///
625 /// # 示例
626 ///
627 /// ```rust
628 /// pub fn xwrust_example_sel() {
629 /// // ...省略...
630 /// let sel0 = Arc::new(Sel::<8>::new());
631 /// sel0.init();
632 /// let sel0sel = match sel0.bind(&sel, 0) {
633 /// Ok(s) => { // 绑定成功,`s` 为 `SelSel`
634 /// s
635 /// },
636 /// Err(e) => { // 绑定失败,`e` 为 `SelError`
637 /// return;
638 /// }
639 /// };
640 /// // ...省略...
641 /// }
642 /// ```
643 ///
644 /// [`SelSel<'a, N, M>`]: SelSel
645 /// [`Ok()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Ok>
646 /// [`Err()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
647 /// [`Sel`]: super::sel::Sel
648 /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
649 pub fn bind<'a, const M: XwSz>(&'a self, dst: &'a Sel<M>, pos: XwSq) ->
650 Result<SelSel<'a, N, M>, SelError>
651 where
652 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
653 {
654 unsafe {
655 let mut rc = xwrustffi_sel_acquire(self.sel.get() as _, *self.tik.get());
656 if rc == 0 {
657 rc = xwrustffi_sel_bind(self.sel.get() as _, dst.sel.get() as _, pos);
658 if XWOK == rc {
659 Ok(SelSel {
660 src: self,
661 dst: dst,
662 pos: pos,
663 })
664 } else if -ECHRNG == rc {
665 Err(SelError::OutOfSelPos(rc))
666 } else if -EALREADY == rc {
667 Err(SelError::AlreadyBound(rc))
668 } else if -EBUSY == rc {
669 Err(SelError::SelPosBusy(rc))
670 } else {
671 Err(SelError::Unknown(rc))
672 }
673 } else {
674 Err(SelError::NotInit(rc))
675 }
676 }
677 }
678}
679
680/// 信号选择器的选择子
681///
682/// `SelSel<'a, N, M>` 与源信号选择器 `src` 与 目的信号选择器 `dst` 具有相同的生命周期约束 `'a` 。因为 `SelSel<'a, N, M>` 中的 `src` 与 `dst` 是引用。
683///
684/// `SelSel<'a, N, M>` 中包含了绑定的位置,信号选择器 采用 **非独占** 的方式进行绑定。
685///
686/// **选择信号** 首先从其他 **同步对象** 发送给 `src` ,再由 `src` 传递给 `dst` 。
687///
688/// [`SelSel::selected()`] 可用来判断信号选择器是否被选择。
689///
690/// 当 `SelSel<'a, N, M>` 被 [`drop()`] 时,会自动将 `src` 从 `dst` 解绑。
691///
692/// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
693pub struct SelSel<'a, const N: XwSz, const M: XwSz>
694where
695 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
696 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
697{
698 src: &'a Sel<N>,
699 dst: &'a Sel<M>,
700 pos: XwSq,
701}
702
703unsafe impl<'a, const N: XwSz, const M: XwSz> Send for SelSel<'a, N, M>
704where
705 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
706 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
707{}
708
709unsafe impl<'a, const N: XwSz, const M: XwSz> Sync for SelSel<'a, N, M>
710where
711 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
712 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
713{}
714
715impl<'a, const N: XwSz, const M: XwSz> Drop for SelSel<'a, N, M>
716where
717 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
718 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
719{
720 fn drop(&mut self) {
721 unsafe {
722 xwrustffi_sel_unbind(self.src.sel.get() as _, self.dst.sel.get() as _);
723 xwrustffi_sel_put(self.src.sel.get() as _);
724 }
725 }
726}
727
728impl<'a, const N: XwSz, const M: XwSz> SelSel<'a, N, M>
729where
730 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
731 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
732{
733 /// 判断触发的 **选择信号** 是否包括此信号选择器
734 ///
735 /// # 示例
736 ///
737 /// ```rust
738 /// let msk = Bmp::<8>::new(); // 8位位图
739 /// msk.s1all(); // 掩码为0xFF
740 /// loop {
741 /// let res = sel.select(&msk);
742 /// match res {
743 /// Ok(t) => { // 信号选择器上有 **选择信号** , `t` 为 **选择信号** 的位图。
744 /// if sel0sel.selected(&t) { // 信号选择器0被选择到
745 /// let msk0 = Bmp::<16>::new(); // 16位位图
746 /// msk0.s1all(); // 掩码为0xFFFF
747 /// let res0 = sel0.tryselect(msk0); // 继续从sel0中选择
748 /// match res0 {
749 /// Ok(t0) => { // 信号选择器0上有 **选择信号** , `t0` 为 **选择信号** 的位图。
750 /// },
751 /// Err(e0) => { // 等待信号选择器0失败,`e` 为 `SelError`
752 /// },
753 /// }
754 /// }
755 /// },
756 /// Err(e) => { // 等待信号选择器失败,`e` 为 `SelError`
757 /// break;
758 /// },
759 /// }
760 /// }
761 /// ```
762 pub fn selected(&self, trg: &Bmp<M>) -> bool {
763 trg.t1i(self.pos)
764 }
765}