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}