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}