Skip to main content

xwrust/xwos/sync/
sem.rs

1//! XWOS RUST:信号量
2//! ========
3//!
4//! 信号量是操作系统比较底层的同步机制,可以同时阻塞一个或多个线程。
5//!
6//! 信号量中包含一个整数值,当信号量的值大于等于0时,信号量可以唤醒一个正在等待的线程。线程被唤醒时会取走一个值,信号量的值减少1。
7//!
8//! 任意上下文都可增加信号量的值,这个操作被称为 **发布** 。
9//!
10//! 信号量常常用于在中断中唤醒一个线程,并将耗时较长的操作放在线程中执行。可减少中断上下文的执行时间,增加中断吞吐量,降低中断延迟。
11//!
12//!
13//! # 创建
14//!
15//! XWOS RUST的信号量可使用 [`Sem::new()`] 创建。
16//!
17//! + 可以创建具有静态生命周期 [`static`] 约束的全局变量:
18//!
19//! ```rust
20//! use xwrust::xwos::sync::sem::*;
21//!
22//! static GLOBAL_SEM: Sem = Sem::new();
23//! ```
24//!
25//! + 也可以使用 [`alloc::sync::Arc`] 在heap中创建:
26//!
27//! ```rust
28//! extern crate alloc;
29//! use alloc::sync::Arc;
30//!
31//! use xwrust::xwos::sync::sem::*;
32//!
33//! pub fn xwrust_example_sem() {
34//!     let sem = Arc::new(Sem::new());
35//! }
36//! ```
37//!
38//!
39//! # 初始化
40//!
41//! 无论以何种方式创建的信号量,都必须在使用前调用 [`Sem::init()`] 进行初始化:
42//!
43//! ```rust
44//! pub fn xwrust_example_sem() {
45//!     GLOBAL_SEM.init(0, XwSsq::MAX);
46//!     sem.init(0, XwSsq::MAX);
47//! }
48//! ```
49//!
50//!
51//! # 发布信号量
52//!
53//! [`Sem::post()`] 方法可用来增加信号量的值。此方法可在 **任意** 上下文使用。
54//! 当信号量的值大与0时,会唤醒信号量等待队列中的一个线程。被唤醒的线程会取走一个值,使得信号量的计数器减1。
55//!
56//!
57//! # 获取信号量
58//!
59//! 当信号量的值大于 **0** 时,可以直接取走一个,此时信号量的值减 **1** ;
60//! 当信号量的值等于 **0** 时,获取信号量的线程就只能阻塞等待,XWOS提供四种方式:
61//!
62//! ## 等待并获取信号量
63//!
64//! [`Sem::wait()`] 方法可用于等待并获取信号量:
65//!
66//! + 若信号量的值小于等于0,线程会阻塞等待。
67//! + 当信号量的值大于0时,线程被唤醒,并取走一个值(信号量的值减少1),然后返回 [`SemError::Ok`] 。
68//! + 当线程阻塞等待被中断时,返回 [`SemError::Interrupt`] 。
69//!
70//! ## 限时等待并获取信号量
71//!
72//! [`Sem::wait_to()`] 方法可用来限时等待并获取信号量:
73//!
74//! + 若信号量的值小于等于0,线程会阻塞等待,等待时会指定一个唤醒时间点。
75//! + 当信号量的值大于0时,线程被唤醒,并取走一个值(信号量的值减少1),然后返回 [`SemError::Ok`] 。
76//! + 当线程阻塞等待被中断时,返回 [`SemError::Interrupt`] 。
77//! + 当到达指定的唤醒时间点,线程被唤醒,并返回 [`SemError::Timedout`] 。
78//!
79//! ## 不可中断等待并获取信号量
80//!
81//! [`Sem::wait_unintr()`] 方法可用来不可中断等待并获取信号量:
82//!
83//! + 若信号量的值小于等于0,线程会阻塞等待,且不可被中断,也不会超时。
84//! + 当信号量的值大于0时,线程被唤醒,并取走一个值(信号量的值减少1),然后返回 [`SemError::Ok`] 。
85//!
86//! ## 尝试获取信号量
87//!
88//! [`Sem::trywait()`] 方法可用来尝试获取信号量:
89//!
90//! + 当信号量的值大于0时,就取走一个值(信号量的值减少1),然后返回 [`SemError::Ok`] 。
91//! + 当信号量的值小于等于0时,立即返回 [`SemError::NoData`] 。
92//!
93//!
94//! # 冻结与解冻
95//!
96//! ## 冻结
97//!
98//! XWOS RUST的信号量可以使用方法 [`Sem::freeze()`] 进行 **冻结** 操作,被冻结的信号量的值为负数,不影响对信号量的 **等待** 操作。
99//! 但不能发布信号量。
100//!
101//! ## 解冻
102//!
103//! 可以通过 [`Sem::thaw()`] 方法将已经冻结的信号量 **解冻**,信号量 **解冻** 后,值被重置为0,此时可重新开始发布信号量。
104//!
105//!
106//! # 获取信号量的最大值
107//!
108//! 可以通过方法 [`Sem::get_max()`] 获取信号量的最大值。
109//!
110//!
111//! # 获取信号量的值
112//!
113//! 可以通过方法 [`Sem::get_value()`] 获取信号量的值,此方法只是读取值,不会 **消费** 信号量。
114//!
115//!
116//! # 绑定到信号选择器
117//!
118//! 信号量是 **同步对象** ,可以通过方法 [`Sem::bind()`] 将信号量绑定到信号选择器 [`Sel<M>`] 上,通过 [`Sel<M>`] ,单一线程可以同时等待多个不同的 **同步对象** 。
119//!
120//! 信号量采用 **独占** 的方式进行绑定。
121//!
122//!
123//! # 示例
124//!
125//! [XWOS/xwam/xwrust-example/xwrust_example_sem](https://gitee.com/xwos/XWOS/blob/main/xwam/xwrust-example/xwrust_example_sem/src/lib.rs)
126//!
127//!
128//! [`static`]: <https://doc.rust-lang.org/std/keyword.static.html>
129//! [`alloc::sync::Arc`]: <https://doc.rust-lang.org/alloc/sync/struct.Arc.html>
130//! [`Sel<M>`]: super::sel::Sel
131
132extern crate core;
133use core::ffi::*;
134use core::cell::UnsafeCell;
135use core::result::Result;
136
137use crate::types::*;
138use crate::errno::*;
139use crate::xwbmp::*;
140use crate::xwos::sync::sel::*;
141
142
143extern "C" {
144    fn xwrustffi_sem_init(sem: *mut XwosSem, val: XwSsq, max: XwSsq) -> XwEr;
145    fn xwrustffi_sem_fini(sem: *mut XwosSem) -> XwEr;
146    fn xwrustffi_sem_grab(sem: *mut XwosSem) -> XwEr;
147    fn xwrustffi_sem_put(sem: *mut XwosSem) -> XwEr;
148    fn xwrustffi_sem_get_tik(sem: *mut XwosSem) -> XwSq;
149    fn xwrustffi_sem_acquire(sem: *mut XwosSem, tik: XwSq) -> XwEr;
150    fn xwrustffi_sem_release(sem: *mut XwosSem, tik: XwSq) -> XwEr;
151    fn xwrustffi_sem_bind(sem: *mut XwosSem, sel: *mut c_void, pos: XwSq) -> XwEr;
152    fn xwrustffi_sem_unbind(sem: *mut XwosSem, sel: *mut c_void) -> XwEr;
153    fn xwrustffi_sem_freeze(sem: *mut XwosSem) -> XwEr;
154    fn xwrustffi_sem_thaw(sem: *mut XwosSem) -> XwEr;
155    fn xwrustffi_sem_post(sem: *mut XwosSem) -> XwEr;
156    fn xwrustffi_sem_wait(sem: *mut XwosSem) -> XwEr;
157    fn xwrustffi_sem_trywait(sem: *mut XwosSem) -> XwEr;
158    fn xwrustffi_sem_wait_to(sem: *mut XwosSem, to: XwTm) -> XwEr;
159    fn xwrustffi_sem_wait_unintr(sem: *mut XwosSem) -> XwEr;
160    fn xwrustffi_sem_get_max(sem: *mut XwosSem, max: *mut XwSsq) -> XwEr;
161    fn xwrustffi_sem_get_value(sem: *mut XwosSem, val: *mut XwSsq) -> XwEr;
162}
163
164/// 信号量的错误码
165#[derive(Debug)]
166pub enum SemError {
167    /// 没有错误
168    Ok(XwEr),
169    /// 信号量没有初始化
170    NotInit(XwEr),
171    /// 信号量已被冻结
172    AlreadyFrozen(XwEr),
173    /// 信号量已解冻
174    AlreadyThawed(XwEr),
175    /// 等待被中断
176    Interrupt(XwEr),
177    /// 等待超时
178    Timedout(XwEr),
179    /// 不在线程上下文内
180    NotThreadContext(XwEr),
181    /// 抢占被关闭
182    DisPmpt(XwEr),
183    /// 中断底半部被关闭
184    DisBh(XwEr),
185    /// 中断被关闭
186    DisIrq(XwEr),
187    /// 信号量不可用
188    NoData(XwEr),
189    /// 信号选择器的位置超出范围
190    OutOfSelPos(XwEr),
191    /// 信号量已经绑定
192    AlreadyBound(XwEr),
193    /// 信号选择器的位置被占用
194    SelPosBusy(XwEr),
195    /// 未知错误
196    Unknown(XwEr),
197}
198
199impl SemError {
200    /// 消费掉 `SemError` 自身,返回内部的错误码。
201    pub fn unwrap(self) -> XwEr {
202        match self {
203            Self::Ok(rc) => rc,
204            Self::NotInit(rc) => rc,
205            Self::AlreadyFrozen(rc) => rc,
206            Self::AlreadyThawed(rc) => rc,
207            Self::Interrupt(rc) => rc,
208            Self::Timedout(rc) => rc,
209            Self::NotThreadContext(rc) => rc,
210            Self::DisPmpt(rc) => rc,
211            Self::DisBh(rc) => rc,
212            Self::DisIrq(rc) => rc,
213            Self::NoData(rc) => rc,
214            Self::OutOfSelPos(rc) => rc,
215            Self::AlreadyBound(rc) => rc,
216            Self::SelPosBusy(rc) => rc,
217            Self::Unknown(rc) => rc,
218        }
219    }
220
221    /// 如果信号量的错误码是 [`SemError::Ok`] ,返回 `true` 。
222    pub const fn is_ok(&self) -> bool {
223        matches!(*self, Self::Ok(_))
224    }
225
226    /// 如果信号量的错误码不是 [`SemError::Ok`] ,返回 `true` 。
227    pub const fn is_err(&self) -> bool {
228        !self.is_ok()
229    }
230}
231
232/// XWOS信号量对象占用的内存大小
233#[cfg(target_pointer_width = "32")]
234pub const SIZEOF_XWOS_SEM: usize = 64;
235
236/// XWOS信号量对象占用的内存大小
237#[cfg(target_pointer_width = "64")]
238pub const SIZEOF_XWOS_SEM: usize = 128;
239
240/// 用于构建信号量的内存数组类型
241#[repr(C)]
242#[cfg_attr(target_pointer_width = "32", repr(align(8)))]
243#[cfg_attr(target_pointer_width = "64", repr(align(16)))]
244pub(crate) struct XwosSem {
245    pub(crate) obj: [u8; SIZEOF_XWOS_SEM],
246}
247
248/// 用于构建信号量的内存数组常量
249///
250/// 此常量的作用是告诉编译器信号量对象需要多大的内存。
251pub(crate) const XWOS_SEM_INITIALIZER: XwosSem = XwosSem {
252    obj: [0; SIZEOF_XWOS_SEM],
253};
254
255/// 信号量对象结构体
256pub struct Sem {
257    /// 用于初始化XWOS信号量对象的内存空间
258    pub(crate) sem: UnsafeCell<XwosSem>,
259    /// 信号量对象的标签
260    pub(crate) tik: UnsafeCell<XwSq>,
261}
262
263unsafe impl Send for Sem {}
264unsafe impl Sync for Sem {}
265
266impl Drop for Sem {
267    fn drop(&mut self) {
268        unsafe {
269            xwrustffi_sem_fini(self.sem.get());
270        }
271    }
272}
273
274impl Sem {
275    /// 新建信号量对象
276    ///
277    /// 此方法是编译期方法。
278    ///
279    /// # 示例
280    ///
281    /// + 具有 [`static`] 约束的全局变量全局变量:
282    ///
283    /// ```rust
284    /// use xwrust::xwos::sync::sem::*;
285    ///
286    /// static GLOBAL_SEM: Sem  = Sem::new();
287    /// ```
288    ///
289    /// + 在heap中创建:
290    ///
291    /// ```rust
292    /// extern crate alloc;
293    /// use alloc::sync::Arc;
294    ///
295    /// pub fn xwrust_example_sem() {
296    ///     let sem = Arc::new(Sem::new());
297    /// }
298    /// ```
299    ///
300    /// [`static`]: https://doc.rust-lang.org/std/keyword.static.html
301    pub const fn new() -> Self {
302        Self {
303            sem: UnsafeCell::new(XWOS_SEM_INITIALIZER),
304            tik: UnsafeCell::new(0),
305        }
306    }
307
308    /// 初始化信号量对象
309    ///
310    /// 信号量对象必须调用此方法一次,方可正常使用。
311    ///
312    /// # 参数说明
313    ///
314    /// + val: 初始值
315    /// + max: 最大值
316    ///
317    /// # 上下文
318    ///
319    /// + 任意
320    ///
321    /// # 示例
322    ///
323    /// ```rust
324    /// use xwrust::types::*;
325    /// use xwrust::xwos::sync::sem::*;
326    ///
327    /// static GLOBAL_SEM: Sem = Sem::new();
328    ///
329    /// pub fn xwrust_example_sem() {
330    ///     // ...省略...
331    ///     GLOBAL_SEM.init(0, XwSsq::max);
332    ///     // 从此处开始 GLOBAL_SEM 可正常使用
333    /// }
334    /// ```
335    pub fn init(&self, val: XwSsq, max: XwSsq) {
336        unsafe {
337            let rc = xwrustffi_sem_acquire(self.sem.get(), *self.tik.get());
338            if rc == 0 {
339                xwrustffi_sem_put(self.sem.get());
340            } else {
341                xwrustffi_sem_init(self.sem.get(), val, max);
342                *self.tik.get() = xwrustffi_sem_get_tik(self.sem.get());
343            }
344        }
345    }
346
347    /// 冻结信号量
348    ///
349    /// 信号量被冻结后,可被线程等待,但被能被单播 [`Sem::post()`] 。
350    ///
351    /// # 上下文
352    ///
353    /// + 任意
354    ///
355    /// # 错误码
356    ///
357    /// + [`SemError::Ok`] 没有错误
358    /// + [`SemError::NotInit`] 信号量没有初始化
359    /// + [`SemError::AlreadyFrozen`] 信号量已被冻结
360    ///
361    /// # 示例
362    ///
363    /// ```rust
364    /// use xwrust::types::*;
365    /// use xwrust::errno::*;
366    /// use xwrust::xwos::sync::sem::*;
367    ///
368    /// pub fn xwrust_example_sem() {
369    ///     // ...省略...
370    ///     let sem: Sem = Sem::new();
371    ///     sem.init(0, XwSsq::max);
372    ///     sem.freeze();
373    /// }
374    /// ```
375    pub fn freeze(&self) -> SemError {
376        unsafe {
377            let mut rc = xwrustffi_sem_acquire(self.sem.get(), *self.tik.get());
378            if rc == 0 {
379                rc = xwrustffi_sem_freeze(self.sem.get());
380                xwrustffi_sem_put(self.sem.get());
381                if XWOK == rc {
382                    SemError::Ok(rc)
383                } else if -EALREADY == rc {
384                    SemError::AlreadyFrozen(rc)
385                } else {
386                    SemError::Unknown(rc)
387                }
388            } else {
389                SemError::NotInit(rc)
390            }
391        }
392    }
393
394    /// 解冻信号量
395    ///
396    /// 被冻结的信号量解冻后,可被单播 [`Sem::post()`] 。
397    ///
398    /// # 上下文
399    ///
400    /// + 任意
401    ///
402    /// # 错误码
403    ///
404    /// + [`SemError::Ok`] 没有错误
405    /// + [`SemError::NotInit`] 信号量没有初始化
406    /// + [`SemError::AlreadyThawed`] 信号量已解冻
407    ///
408    /// # 示例
409    ///
410    /// ```rust
411    /// use xwrust::types::*;
412    /// use xwrust::errno::*;
413    /// use xwrust::xwos::sync::sem::*;
414    ///
415    /// pub fn xwrust_example_sem() {
416    ///     // ...省略...
417    ///     let sem: Sem = Sem::new();
418    ///     sem.init(0, XwSsq::max);
419    ///     sem.freeze(); // 冻结
420    ///     // ...省略...
421    ///     sem.thaw(); // 解冻
422    /// }
423    /// ```
424    pub fn thaw(&self) -> SemError {
425        unsafe {
426            let mut rc = xwrustffi_sem_acquire(self.sem.get(), *self.tik.get());
427            if rc == 0 {
428                rc = xwrustffi_sem_thaw(self.sem.get());
429                xwrustffi_sem_put(self.sem.get());
430                if XWOK == rc {
431                    SemError::Ok(rc)
432                } else if -EALREADY == rc {
433                    SemError::AlreadyThawed(rc)
434                } else {
435                    SemError::Unknown(rc)
436                }
437            } else {
438                SemError::NotInit(rc)
439            }
440        }
441    }
442
443    /// 发布信号量
444    ///
445    /// # 上下文
446    ///
447    /// + 任意
448    ///
449    /// # 错误码
450    ///
451    /// + [`SemError::Ok`] 没有错误
452    /// + [`SemError::NotInit`] 信号量没有初始化
453    /// + [`SemError::AlreadyFrozen`] 信号量已被冻结
454    ///
455    /// # 示例
456    ///
457    /// ```rust
458    /// use xwrust::types::*;
459    /// use xwrust::errno::*;
460    /// use xwrust::xwos::sync::sem::*;
461    ///
462    /// pub fn xwrust_example_sem() {
463    ///     // ...省略...
464    ///     let sem: Sem = Sem::new();
465    ///     sem.init(0, XwSsq::max);
466    ///     // ...省略...
467    ///     sem.post();
468    /// }
469    /// ```
470    pub fn post(&self) -> SemError {
471        unsafe {
472            let mut rc = xwrustffi_sem_acquire(self.sem.get(), *self.tik.get());
473            if rc == 0 {
474                rc = xwrustffi_sem_post(self.sem.get());
475                xwrustffi_sem_put(self.sem.get());
476                if XWOK == rc {
477                    SemError::Ok(rc)
478                } else if -ENEGATIVE == rc {
479                    SemError::AlreadyFrozen(rc)
480                } else {
481                    SemError::Unknown(rc)
482                }
483            } else {
484                SemError::NotInit(rc)
485            }
486        }
487    }
488
489    /// 获取信号量对象计数器的最大值
490    ///
491    /// 成功将在 [`Ok()`] 中返回信号量对象计数器的值。
492    ///
493    /// # 错误码
494    ///
495    /// + Err([`SemError::NotInit`]) 信号量没有初始化
496    ///
497    /// # 示例
498    ///
499    /// ```rust
500    /// use xwrust::types::*;
501    /// use xwrust::errno::*;
502    /// use xwrust::xwos::sync::sem::*;
503    ///
504    /// pub fn xwrust_example_sem() {
505    ///     // ...省略...
506    ///     let sem: Sem = Sem::new();
507    ///     sem.init(0, XwSsq::MAX);
508    ///     // ...省略...
509    ///     let res = sem.get_max();
510    ///     match res {
511    ///         Ok(max) => {
512    ///             // 返回信号量的值
513    ///         },
514    ///         Err(e) => {
515    ///             // 返回错误码
516    ///         },
517    ///     };
518    /// }
519    /// ```
520    ///
521    /// [`Ok()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Ok>
522    pub fn get_max(&self) -> Result<XwSsq, SemError> {
523        unsafe {
524            let rc = xwrustffi_sem_acquire(self.sem.get(), *self.tik.get());
525            if rc == 0 {
526                let mut max: XwSsq = 0;
527                xwrustffi_sem_get_max(self.sem.get(), &mut max);
528                xwrustffi_sem_put(self.sem.get());
529                Ok(max)
530            } else {
531                Err(SemError::NotInit(rc))
532            }
533        }
534    }
535
536    /// 获取信号量对象计数器的值
537    ///
538    /// 成功将在 [`Ok()`] 中返回信号量对象计数器的值。
539    ///
540    /// # 错误码
541    ///
542    /// + Err([`SemError::NotInit`]) 信号量没有初始化
543    ///
544    /// # 示例
545    ///
546    /// ```rust
547    /// use xwrust::types::*;
548    /// use xwrust::errno::*;
549    /// use xwrust::xwos::sync::sem::*;
550    ///
551    /// pub fn xwrust_example_sem() {
552    ///     // ...省略...
553    ///     let sem: Sem = Sem::new();
554    ///     sem.init(0, XwSsq::MAX);
555    ///     // ...省略...
556    ///     let res = sem.get_value();
557    ///     match res {
558    ///         Ok(val) => {
559    ///             // 返回信号量的值
560    ///         },
561    ///         Err(e) => {
562    ///             // 返回错误码
563    ///         },
564    ///     };
565    /// }
566    /// ```
567    ///
568    /// [`Ok()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Ok>
569    pub fn get_value(&self) -> Result<XwSsq, SemError> {
570        unsafe {
571            let rc = xwrustffi_sem_acquire(self.sem.get(), *self.tik.get());
572            if rc == 0 {
573                let mut val: XwSsq = 0;
574                xwrustffi_sem_get_value(self.sem.get(), &mut val);
575                xwrustffi_sem_put(self.sem.get());
576                Ok(val)
577            } else {
578                Err(SemError::NotInit(rc))
579            }
580        }
581    }
582
583    /// 等待并获取信号量
584    ///
585    /// + 若信号量的值小于等于0,线程会阻塞等待。
586    /// + 当信号量的值大于0时,线程被唤醒,并取走一个值(信号量的值减少1),然后返回 [`SemError::Ok`] 。
587    /// + 当线程阻塞等待被中断时,返回 [`SemError::Interrupt`] 。
588    ///
589    /// # 上下文
590    ///
591    /// + 线程
592    ///
593    /// # 错误码
594    ///
595    /// + [`SemError::Ok`] 没有错误
596    /// + [`SemError::NotInit`] 信号量没有初始化
597    /// + [`SemError::Interrupt`] 等待被中断
598    /// + [`SemError::NotThreadContext`] 不在线程上下文内
599    /// + [`SemError::DisPmpt`] 抢占被关闭
600    /// + [`SemError::DisBh`] 中断底半部被关闭
601    /// + [`SemError::DisIrq`] 中断被关闭
602    ///
603    /// # 示例
604    ///
605    /// ```rust
606    /// use xwrust::types::*;
607    /// use xwrust::xwos::sync::sem::*;
608    ///
609    /// pub fn xwrust_example_sem() {
610    ///     // ...省略...
611    ///     let sem: Sem = Sem::new();
612    ///     sem.init(0, XwSsq::max);
613    ///     // ...省略...
614    ///     let rc = sem.wait();
615    ///     match rc {
616    ///         SemError::Ok => {
617    ///             // 获取信号量
618    ///         },
619    ///         _ => {
620    ///             // 等待信号量失败
621    ///         },
622    ///     };
623    /// }
624    /// ```
625    pub fn wait(&self) -> SemError {
626        unsafe {
627            let mut rc = xwrustffi_sem_acquire(self.sem.get(), *self.tik.get());
628            if rc == 0 {
629                rc = xwrustffi_sem_wait(self.sem.get());
630                xwrustffi_sem_put(self.sem.get());
631                if XWOK == rc {
632                    SemError::Ok(rc)
633                } else if -EINTR == rc {
634                    SemError::Interrupt(rc)
635                } else if -ENOTTHDCTX == rc {
636                    SemError::NotThreadContext(rc)
637                } else if -EDISPMPT == rc {
638                    SemError::DisPmpt(rc)
639                } else if -EDISBH == rc {
640                    SemError::DisBh(rc)
641                } else if -EDISIRQ == rc {
642                    SemError::DisIrq(rc)
643                } else {
644                    SemError::Unknown(rc)
645                }
646            } else {
647                SemError::NotInit(rc)
648            }
649        }
650    }
651
652    /// 限时等待并获取信号量
653    ///
654    /// + 若信号量的值小于等于0,线程会阻塞等待,等待时会指定一个唤醒时间点。
655    /// + 当信号量的值大于0时,线程被唤醒,并取走一个值(信号量的值减少1),然后返回 [`SemError::Ok`] 。
656    /// + 当线程阻塞等待被中断时,返回 [`SemError::Interrupt`] 。
657    /// + 当到达指定的唤醒时间点,线程被唤醒,并返回 [`SemError::Timedout`] 。
658    /// + 如果 `to` 是过去的时间点,将直接返回 [`SemError::Timedout`] 。
659    ///
660    /// # 参数说明
661    ///
662    /// + to: 期望唤醒的时间点
663    ///
664    /// # 上下文
665    ///
666    /// + 线程
667    ///
668    /// # 错误码
669    ///
670    /// + [`SemError::Ok`] 没有错误
671    /// + [`SemError::NotInit`] 信号量没有初始化
672    /// + [`SemError::Interrupt`] 等待被中断
673    /// + [`SemError::Timedout`] 等待超时
674    /// + [`SemError::NotThreadContext`] 不在线程上下文内
675    /// + [`SemError::DisPmpt`] 抢占被关闭
676    /// + [`SemError::DisBh`] 中断底半部被关闭
677    /// + [`SemError::DisIrq`] 中断被关闭
678    ///
679    /// # 示例
680    ///
681    /// ```rust
682    /// use xwrust::types::*;
683    /// use xwrust::errno::*;
684    /// use xwrust::xwos::sync::sem::*;
685    ///
686    /// pub fn xwrust_example_sem() {
687    ///     // ...省略...
688    ///     let sem: Sem = Sem::new();
689    ///     sem.init(0, XwSsq::max);
690    ///     // ...省略...
691    ///     let rc = sem.wait_to(xwtm::ft(xwtm::s(1))); // 最多等待1s
692    ///     match rc {
693    ///         SemError::Ok => {
694    ///             // 获取信号量
695    ///         },
696    ///         _ => {
697    ///             // 等待信号量失败
698    ///         },
699    ///     };
700    /// }
701    /// ```
702    pub fn wait_to(&self, to: XwTm) -> SemError {
703        unsafe {
704            let mut rc = xwrustffi_sem_acquire(self.sem.get(), *self.tik.get());
705            if rc == 0 {
706                rc = xwrustffi_sem_wait_to(self.sem.get(), to);
707                xwrustffi_sem_put(self.sem.get());
708                if XWOK == rc {
709                    SemError::Ok(rc)
710                } else if -EINTR == rc {
711                    SemError::Interrupt(rc)
712                } else if -ETIMEDOUT == rc {
713                    SemError::Timedout(rc)
714                } else if -ENOTTHDCTX == rc {
715                    SemError::NotThreadContext(rc)
716                } else if -EDISPMPT == rc {
717                    SemError::DisPmpt(rc)
718                } else if -EDISBH == rc {
719                    SemError::DisBh(rc)
720                } else if -EDISIRQ == rc {
721                    SemError::DisIrq(rc)
722                } else {
723                    SemError::Unknown(rc)
724                }
725            } else {
726                SemError::NotInit(rc)
727            }
728        }
729    }
730
731    /// 等待并获取信号量,且等待不可被中断
732    ///
733    /// + 若信号量的值小于等于0,线程会阻塞等待,且不可被中断,也不会超时。
734    /// + 当信号量的值大于0时,线程被唤醒,并取走一个值(信号量的值减少1),然后返回 [`SemError::Ok`] 。
735    ///
736    /// # 上下文
737    ///
738    /// + 线程
739    ///
740    /// # 错误码
741    ///
742    /// + [`SemError::Ok`] 没有错误
743    /// + [`SemError::NotInit`] 信号量没有初始化
744    /// + [`SemError::NotThreadContext`] 不在线程上下文内
745    /// + [`SemError::DisPmpt`] 抢占被关闭
746    /// + [`SemError::DisBh`] 中断底半部被关闭
747    /// + [`SemError::DisIrq`] 中断被关闭
748    ///
749    /// # 示例
750    ///
751    /// ```rust
752    /// use xwrust::types::*;
753    /// use xwrust::errno::*;
754    /// use xwrust::xwos::sync::sem::*;
755    ///
756    /// pub fn xwrust_example_sem() {
757    ///     // ...省略...
758    ///     let sem: Sem = Sem::new();
759    ///     sem.init(0, XwSsq::max);
760    ///     // ...省略...
761    ///     let rc = sem.wait_unintr();
762    ///     match rc {
763    ///         SemError::Ok => {
764    ///             // 获取信号量
765    ///         },
766    ///         _ => {
767    ///             // 等待信号量失败
768    ///         },
769    ///     };
770    /// }
771    /// ```
772    pub fn wait_unintr(&self) -> SemError {
773        unsafe {
774            let mut rc = xwrustffi_sem_acquire(self.sem.get(), *self.tik.get());
775            if rc == 0 {
776                rc = xwrustffi_sem_wait_unintr(self.sem.get());
777                xwrustffi_sem_put(self.sem.get());
778                if XWOK == rc {
779                    SemError::Ok(rc)
780                } else if -ENOTTHDCTX == rc {
781                    SemError::NotThreadContext(rc)
782                } else if -EDISPMPT == rc {
783                    SemError::DisPmpt(rc)
784                } else if -EDISBH == rc {
785                    SemError::DisBh(rc)
786                } else if -EDISIRQ == rc {
787                    SemError::DisIrq(rc)
788                } else {
789                    SemError::Unknown(rc)
790                }
791            } else {
792                SemError::NotInit(rc)
793            }
794        }
795    }
796
797    /// 尝试获取信号量
798    ///
799    /// + 当信号量的值大于0时,就取走一个值(信号量的值减少1),然后返回 [`SemError::Ok`] 。
800    /// + 当信号量的值小于等于0时,立即返回 [`SemError::NoData`] 。
801    ///
802    /// # 上下文
803    ///
804    /// + 任意
805    ///
806    /// # 错误码
807    ///
808    /// + [`SemError::Ok`] 没有错误
809    /// + [`SemError::NotInit`] 信号量没有初始化
810    /// + [`SemError::NoData`] 信号量不可用
811    ///
812    /// # 示例
813    ///
814    /// ```rust
815    /// use xwrust::types::*;
816    /// use xwrust::errno::*;
817    /// use xwrust::xwos::sync::sem::*;
818    ///
819    /// pub fn xwrust_example_sem() {
820    ///     // ...省略...
821    ///     let sem: Sem = Sem::new();
822    ///     sem.init(0, XwSsq::max);
823    ///     // ...省略...
824    ///     let rc = sem.trywait();
825    ///     match rc {
826    ///         SemError::Ok => {
827    ///             // 获取信号量
828    ///         },
829    ///         _ => {
830    ///             // 等待信号量失败
831    ///         },
832    ///     };
833    /// }
834    /// ```
835    pub fn trywait(&self) -> SemError {
836        unsafe {
837            let mut rc = xwrustffi_sem_acquire(self.sem.get(), *self.tik.get());
838            if rc == 0 {
839                rc = xwrustffi_sem_trywait(self.sem.get());
840                xwrustffi_sem_put(self.sem.get());
841                if XWOK == rc {
842                    SemError::Ok(rc)
843                } else if -ENODATA == rc {
844                    SemError::NoData(rc)
845                } else {
846                    SemError::Unknown(rc)
847                }
848            } else {
849                SemError::NotInit(rc)
850            }
851        }
852    }
853
854    /// 绑定信号量对象到信号选择器
855    ///
856    /// + 信号量绑定到信号选择器上时, **独占** 一个位置。
857    /// + 绑定成功,通过 [`Ok()`] 返回 [`SemSel<'a, M>`] 。
858    /// + 如果位置已被占领,通过 [`Err()`] 返回 [`SemError::SelPosBusy`] 。
859    /// + 当指定的位置超出范围(例如 [`Sel<M>`] 只有8个位置,用户偏偏要绑定到位置9 ),通过 [`Err()`] 返回 [`SemError::OutOfSelPos`] 。
860    /// + 重复绑定,通过 [`Err()`] 返回 [`SemError::AlreadyBound`] 。
861    ///
862    /// [`SemSel<'a, M>`] 中包含信号量的绑定信息。 [`SemSel<'a, M>`] 与 [`Sem`] 与 [`Sel<M>`] 具有相同的生命周期约束 `'a` 。
863    /// [`SemSel::selected()`] 可用来判断信号量是否被选择。当 [`SemSel<'a, M>`] [`drop()`] 时,会自动解绑。
864    ///
865    /// # 参数说明
866    ///
867    /// + sel: 信号选择器的引用
868    /// + pos: 位置
869    ///
870    /// # 上下文
871    ///
872    /// + 任意
873    ///
874    /// # 错误码
875    ///
876    /// + [`SemError::OutOfSelPos`] 信号选择器的位置超出范围
877    /// + [`SemError::AlreadyBound`] 信号量已经绑定
878    /// + [`SemError::SelPosBusy`] 信号选择器的位置被占用
879    ///
880    /// # 示例
881    ///
882    /// ```rust
883    /// pub fn xwrust_example_sel() {
884    ///     // ...省略...
885    ///     let sem0 = Arc::new(Sem::new());
886    ///     sem0.init(0, XwSsq::MAX);
887    ///     let sem0sel = match sem0.bind(&sel, 0) {
888    ///         Ok(s) => { // 绑定成功,`s` 为 `SemSel`
889    ///             s
890    ///         },
891    ///         Err(e) => { // 绑定失败,`e` 为 `SelError`
892    ///             return;
893    ///         }
894    ///     };
895    ///     // ...省略...
896    /// }
897    /// ```
898    ///
899    /// [`SemSel<'a, M>`]: SemSel
900    /// [`Ok()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Ok>
901    /// [`Err()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
902    /// [`Sel<M>`]: super::sel::Sel
903    /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
904    pub fn bind<'a, const M: XwSz>(&'a self, sel: &'a Sel<M>, pos: XwSq)
905                                   -> Result<SemSel<'a, M>, SemError>
906    where
907        [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
908    {
909        unsafe {
910            let mut rc = xwrustffi_sem_acquire(self.sem.get(), *self.tik.get());
911            if rc == 0 {
912                rc = xwrustffi_sem_bind(self.sem.get(), sel.sel.get() as _, pos);
913                if XWOK == rc {
914                    Ok(SemSel {
915                        sem: self,
916                        sel: sel,
917                        pos: pos,
918                    })
919                } else if -ECHRNG == rc {
920                    Err(SemError::OutOfSelPos(rc))
921                } else if -EALREADY == rc {
922                    Err(SemError::AlreadyBound(rc))
923                } else if -EBUSY == rc {
924                    Err(SemError::SelPosBusy(rc))
925                } else {
926                    Err(SemError::Unknown(rc))
927                }
928            } else {
929                Err(SemError::NotInit(rc))
930            }
931        }
932    }
933}
934
935/// 信号量的选择子
936///
937/// `SemSel<'a, M>` 与 [`Sem`] 与 [`Sel<M>`] 具有相同的生命周期约束 `'a` 。因为 `SemSel<'a, M>` 中包含了 [`Sem`] 与 [`Sel<M>`] 的引用。
938///
939/// `SemSel<'a, M>` 中包含了绑定的位置,信号量 **独占** 一个位置。
940///
941/// [`SemSel::selected()`] 可用来判断信号量是否被选择。
942///
943/// 当 `SemSel<'a, M>` 被 [`drop()`] 时,会自动将 [`Sem`] 从 [`Sel<M>`] 解绑。
944///
945/// [`Sel<M>`]: super::sel::Sel
946/// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
947pub struct SemSel<'a, const M: XwSz>
948where
949    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
950{
951    sem: &'a Sem,
952    sel: &'a Sel<M>,
953    pos: XwSq,
954}
955
956unsafe impl<'a, const M: XwSz> Send for SemSel<'a, M>
957where
958    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
959{}
960
961unsafe impl<'a, const M: XwSz> Sync for SemSel<'a, M>
962where
963    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
964{}
965
966impl<'a, const M: XwSz> Drop for SemSel<'a, M>
967where
968    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
969{
970    fn drop(&mut self) {
971        unsafe {
972            xwrustffi_sem_unbind(self.sem.sem.get(), self.sel.sel.get() as _);
973            xwrustffi_sem_put(self.sem.sem.get());
974        }
975    }
976}
977
978impl<'a, const M: XwSz> SemSel<'a, M>
979where
980    [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
981{
982    /// 判断触发的 **选择信号** 是否包括此信号量
983    ///
984    /// # 示例
985    ///
986    /// ```rust
987    ///     let msk = Bmp::<8>::new(); // 8位位图
988    ///     msk.s1all(); // 掩码为0xFF
989    ///     loop {
990    ///         let res = sel.select(&msk);
991    ///         match res {
992    ///             Ok(t) => { // 信号选择器上有 **选择信号** , `t` 为 **选择信号** 的位图。
993    ///                 if sem0sel.selected(&t) { // 信号量0被选择到
994    ///                     sem0.trywait();
995    ///                 }
996    ///                 if sem1sel.selected(&t) { // 信号量1被选择到
997    ///                     sem1.trywait();
998    ///                 }
999    ///             },
1000    ///             Err(e) => { // 等待信号选择器失败,`e` 为 `SelError`
1001    ///                 break;
1002    ///             },
1003    ///         }
1004    ///     }
1005    /// ```
1006    pub fn selected(&self, trg: &Bmp<M>) -> bool {
1007        trg.t1i(self.pos)
1008    }
1009}