xwrust/xwos/sync/br.rs
1//! XWOS RUST:线程栅栏
2//! ========
3//!
4//! 线程栅栏是用于协调多个线程并行工作的同步机制。
5//!
6//! 线程栅栏在创建时,会指明有多少个线程槽。
7//! 当线程到达线程栅栏时会阻塞并等待,直到指定数量的线程都达到线程栅栏,所有线程被同时唤醒。
8//!
9//!
10//! # 创建
11//!
12//! XWOS RUST的线程栅栏可使用 [`Br::new()`] 创建。
13//!
14//! + 可以创建具有静态生命周期 [`static`] 约束的全局变量:
15//!
16//! ```rust
17//! use xwrust::xwos::sync::br::*;
18//!
19//! static GLOBAL_BR: Br<8> = Br::new();
20//! ```
21//!
22//! + 也可以使用 [`alloc::sync::Arc`] 在heap中创建:
23//!
24//! ```rust
25//! extern crate alloc;
26//! use alloc::sync::Arc;
27//!
28//! use xwrust::xwos::sync::br::*;
29//!
30//! pub fn xwrust_example_br() {
31//! let br = Arc::new(Br::<8>::new());
32//! }
33//! ```
34//!
35//!
36//! # 初始化
37//!
38//! 无论以何种方式创建的线程栅栏,都必须在使用前调用 [`Br::init()`] 进行初始化:
39//!
40//! ```rust
41//! pub fn xwrust_example_br() {
42//! GLOBAL_BR.init();
43//! br.init();
44//! }
45//! ```
46//!
47//!
48//! ## 等待所有线程到达栅栏
49//!
50//! [`Br::wait()`] 可用于等待所有线程到达栅栏。
51//!
52//! + 当线程栅栏中的线程数量小于指定数量,线程会阻塞等待。
53//! + 当线程栅栏中的线程数量达到指定数量,全部线程被唤醒,然后返回 [`BrError::Ok`] 。
54//! + 当线程阻塞等待被中断时,返回 [`BrError::Interrupt`] 。
55//!
56//! ## 限时等待所有线程到达栅栏
57//!
58//! [`Br::wait_to()`] 可用于限时等待所有线程到达栅栏。
59//!
60//! + 当线程栅栏中的线程数量小于指定数量,线程会阻塞等待,等待时会指定一个唤醒时间点。
61//! + 当线程栅栏中的线程数量达到指定数量,全部线程被唤醒,然后返回 [`BrError::Ok`] 。
62//! + 当线程阻塞等待被中断时,返回 [`BrError::Interrupt`] 。
63//! + 当到达指定的唤醒时间点,线程被唤醒,并返回 [`BrError::Timedout`] 。
64//!
65//!
66//! # 获取线程栅栏中线程槽的数量
67//!
68//! 可以通过方法 [`Br::get_num()`] 获取线程栅栏中线程槽的数量。
69//!
70//!
71//! # 绑定到信号选择器
72//!
73//! 线程栅栏是 **同步对象** ,可以通过方法 [`Br::bind()`] 将线程栅栏绑定到信号选择器 [`Sel<M>`] 上,通过 [`Sel<M>`] ,单一线程可以同时等待多个不同的 **同步对象** 。
74//!
75//! 线程栅栏采用 **非独占** 的方式进行绑定。
76//!
77//!
78//! # 示例
79//!
80//! [XWOS/xwam/xwrust-example/xwrust_example_br](https://gitee.com/xwos/XWOS/blob/main/xwam/xwrust-example/xwrust_example_br/src/lib.rs)
81//!
82//!
83//! [`static`]: <https://doc.rust-lang.org/std/keyword.static.html>
84//! [`alloc::sync::Arc`]: <https://doc.rust-lang.org/alloc/sync/struct.Arc.html>
85//! [`Sel<M>`]: super::sel::Sel
86
87extern crate core;
88use core::ffi::*;
89use core::cell::UnsafeCell;
90
91use crate::types::*;
92use crate::errno::*;
93use crate::xwbmp::*;
94use crate::xwos::sync::sel::*;
95
96
97extern "C" {
98 pub(crate) fn xwrustffi_br_init(br: *mut c_void, num: XwSz, bmp: *mut XwBmp, msk: *mut XwBmp) -> XwEr;
99 pub(crate) fn xwrustffi_br_fini(br: *mut c_void) -> XwEr;
100 pub(crate) fn xwrustffi_br_grab(br: *mut c_void) -> XwEr;
101 pub(crate) fn xwrustffi_br_put(br: *mut c_void) -> XwEr;
102 pub(crate) fn xwrustffi_br_get_tik(br: *mut c_void) -> XwSq;
103 pub(crate) fn xwrustffi_br_acquire(br: *mut c_void, tik: XwSq) -> XwEr;
104 pub(crate) fn xwrustffi_br_release(br: *mut c_void, tik: XwSq) -> XwEr;
105 pub(crate) fn xwrustffi_br_bind(br: *mut c_void, sel: *mut c_void, pos: XwSq) -> XwEr;
106 pub(crate) fn xwrustffi_br_unbind(br: *mut c_void, sel: *mut c_void) -> XwEr;
107 pub(crate) fn xwrustffi_br_wait(br: *mut c_void) -> XwEr;
108 pub(crate) fn xwrustffi_br_wait_to(br: *mut c_void, to: XwTm) -> XwEr;
109}
110
111/// 线程栅栏的错误码
112#[derive(Debug)]
113pub enum BrError {
114 /// 没有错误
115 Ok(XwEr),
116 /// 线程栅栏没有初始化
117 NotInit(XwEr),
118 /// 线程数量超出范围
119 OutOfRange(XwEr),
120 /// 等待被中断
121 Interrupt(XwEr),
122 /// 等待超时
123 Timedout(XwEr),
124 /// 不在线程上下文内
125 NotThreadContext(XwEr),
126 /// 信号选择器的位置超出范围
127 OutOfSelPos(XwEr),
128 /// 事件标志已经绑定
129 AlreadyBound(XwEr),
130 /// 信号选择器的位置被占用
131 SelPosBusy(XwEr),
132 /// 未知错误
133 Unknown(XwEr),
134}
135
136impl BrError {
137 /// 消费掉 `BrError` 自身,返回内部的错误码。
138 pub fn unwrap(self) -> XwEr {
139 match self {
140 Self::Ok(rc) => rc,
141 Self::NotInit(rc) => rc,
142 Self::OutOfRange(rc) => rc,
143 Self::Interrupt(rc) => rc,
144 Self::Timedout(rc) => rc,
145 Self::NotThreadContext(rc) => rc,
146 Self::OutOfSelPos(rc) => rc,
147 Self::AlreadyBound(rc) => rc,
148 Self::SelPosBusy(rc) => rc,
149 Self::Unknown(rc) => rc,
150 }
151 }
152
153 /// 如果错误码是 [`BrError::Ok`] ,返回 `true` 。
154 pub const fn is_ok(&self) -> bool {
155 matches!(*self, Self::Ok(_))
156 }
157
158 /// 如果错误码不是 [`BrError::Ok`] ,返回 `true` 。
159 pub const fn is_err(&self) -> bool {
160 !self.is_ok()
161 }
162}
163
164/// XWOS线程栅栏对象占用的内存大小
165#[cfg(target_pointer_width = "32")]
166pub const SIZEOF_XWOS_BR: usize = 64;
167
168/// XWOS线程栅栏对象占用的内存大小
169#[cfg(target_pointer_width = "64")]
170pub const SIZEOF_XWOS_BR: usize = 128;
171
172/// 用于构建线程栅栏的内存数组类型
173#[repr(C)]
174#[cfg_attr(target_pointer_width = "32", repr(align(8)))]
175#[cfg_attr(target_pointer_width = "64", repr(align(16)))]
176pub(crate) struct XwosBr<const N: XwSz>
177where
178 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
179{
180 pub(crate) obj: [u8; SIZEOF_XWOS_BR],
181 pub(crate) bmp: [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
182 pub(crate) msk: [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
183}
184
185/// 线程栅栏对象结构体
186pub struct Br<const N: XwSz>
187where
188 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
189{
190 /// 用于初始化XWOS线程栅栏对象的内存空间
191 pub(crate) br: UnsafeCell<XwosBr<N>>,
192 /// 线程栅栏对象的标签
193 pub(crate) tik: UnsafeCell<XwSq>,
194}
195
196unsafe impl<const N: XwSz> Send for Br<N>
197where
198 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
199{}
200
201unsafe impl<const N: XwSz> Sync for Br<N>
202where
203 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
204{}
205
206impl<const N: XwSz> Drop for Br<N>
207where
208 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
209{
210 fn drop(&mut self) {
211 unsafe {
212 xwrustffi_br_fini(self.br.get() as _);
213 }
214 }
215}
216
217impl<const N: XwSz> Br<N>
218where
219 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
220{
221 /// 新建线程栅栏对象
222 ///
223 /// 此方法是编译期方法。
224 ///
225 /// # 示例
226 ///
227 /// + 具有 [`static`] 约束的全局变量全局变量:
228 ///
229 /// ```rust
230 /// use xwrust::xwos::sync::br::*;
231 ///
232 /// static GLOBAL_BR: Br<8> = Br::new();
233 /// ```
234 ///
235 /// + 在heap中创建:
236 ///
237 /// ```rust
238 /// extern crate alloc;
239 /// use alloc::sync::Arc;
240 ///
241 /// pub fn xwrust_example_br() {
242 /// let br = Arc::new(Br::<8>::new());
243 /// }
244 /// ```
245 ///
246 /// [`static`]: https://doc.rust-lang.org/std/keyword.static.html
247 pub const fn new() -> Self {
248 Self {
249 br: UnsafeCell::new(XwosBr {
250 obj: [0; SIZEOF_XWOS_BR],
251 bmp: [0; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
252 msk: [0; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize],
253 }),
254 tik: UnsafeCell::new(0),
255 }
256 }
257
258 /// 初始化线程栅栏对象
259 ///
260 /// 线程栅栏对象必须调用此方法一次,方可正常使用。
261 ///
262 /// # 上下文
263 ///
264 /// + 任意
265 ///
266 /// # 示例
267 ///
268 /// ```rust
269 /// use xwrust::xwos::sync::br::*;
270 ///
271 /// static GLOBAL_BR: Br<8> = Br::new();
272 ///
273 /// pub fn xwrust_example_br() {
274 /// // ...省略...
275 /// GLOBAL_BR.init();
276 /// // 从此处开始 GLOBAL_BR 可正常使用
277 /// }
278 /// ```
279 pub fn init(&self) {
280 unsafe {
281 let rc = xwrustffi_br_acquire(self.br.get() as _, *self.tik.get());
282 if rc == 0 {
283 xwrustffi_br_put(self.br.get() as _);
284 } else {
285 xwrustffi_br_init(self.br.get() as _,
286 N,
287 &mut (*self.br.get()).bmp as _,
288 &mut (*self.br.get()).msk as _);
289 *self.tik.get() = xwrustffi_br_get_tik(self.br.get() as _);
290 }
291 }
292 }
293
294 /// 获取线程栅栏中线程槽的数量
295 pub const fn get_num(&self) -> XwSz {
296 N
297 }
298
299 /// 等待所有线程到达栅栏
300 ///
301 /// + 当线程栅栏中的线程数量小于指定数量,线程会阻塞等待。
302 /// + 当线程栅栏中的线程数量达到指定数量,全部线程被唤醒,然后返回 [`BrError::Ok`] 。
303 /// + 当线程阻塞等待被中断时,返回 [`BrError::Interrupt`] 。
304 ///
305 /// # 上下文
306 ///
307 /// + 线程
308 ///
309 /// # 错误码
310 ///
311 /// + [`BrError::Ok`] 没有错误
312 /// + [`BrError::NotInit`] 线程栅栏没有初始化
313 /// + [`BrError::OutOfRange`] 线程数量超出范围
314 /// + [`BrError::Interrupt`] 等待被中断
315 /// + [`BrError::NotThreadContext`] 不在线程上下文内
316 ///
317 /// # 示例
318 ///
319 /// ```rust
320 /// extern crate alloc;
321 /// use alloc::sync::Arc;
322 ///
323 /// use xwrust::xwos::sync::br::*;
324 ///
325 /// pub fn xwrust_example_br() {
326 /// let br = Arc::new(Br::<8>::new());
327 /// br.init();
328 /// for idx in 0..8 {
329 /// let c = br.clone();
330 /// let _ = thd::spawn(move |_| { // 子线程闭包
331 /// c.wait();
332 /// });
333 /// }
334 /// }
335 /// ```
336 pub fn wait(&self) -> BrError {
337 unsafe {
338 let mut rc = xwrustffi_br_acquire(self.br.get() as _, *self.tik.get());
339 if rc == 0 {
340 rc = xwrustffi_br_wait(self.br.get() as _);
341 xwrustffi_br_put(self.br.get() as _);
342 if XWOK == rc {
343 BrError::Ok(rc)
344 } else if -ECHRNG == rc {
345 BrError::OutOfRange(rc)
346 } else if -EINTR == rc {
347 BrError::Interrupt(rc)
348 } else if -ENOTTHDCTX == rc {
349 BrError::NotThreadContext(rc)
350 } else {
351 BrError::Unknown(rc)
352 }
353 } else {
354 BrError::NotInit(rc)
355 }
356 }
357 }
358
359 /// 限时等待所有线程到达栅栏
360 ///
361 /// + 当线程栅栏中的线程数量小于指定数量,线程会阻塞等待,等待时会指定一个唤醒时间点。
362 /// + 当线程栅栏中的线程数量达到指定数量,全部线程被唤醒,然后返回 [`BrError::Ok`] 。
363 /// + 当线程阻塞等待被中断时,返回 [`BrError::Interrupt`] 。
364 /// + 当到达指定的唤醒时间点,线程被唤醒,并返回 [`BrError::Timedout`] 。
365 ///
366 /// # 参数说明
367 ///
368 /// + to: 期望唤醒的时间点
369 ///
370 /// # 上下文
371 ///
372 /// + 线程
373 ///
374 /// # 错误码
375 ///
376 /// + [`BrError::Ok`] 没有错误
377 /// + [`BrError::NotInit`] 线程栅栏没有初始化
378 /// + [`BrError::OutOfRange`] 线程数量超出范围
379 /// + [`BrError::Interrupt`] 等待被中断
380 /// + [`BrError::Timedout`] 等待超时
381 /// + [`BrError::NotThreadContext`] 不在线程上下文内
382 ///
383 /// # 示例
384 ///
385 /// ```rust
386 /// extern crate alloc;
387 /// use alloc::sync::Arc;
388 ///
389 /// use xwrust::xwos::sync::br::*;
390 ///
391 /// pub fn xwrust_example_br() {
392 /// let br = Arc::new(Br::<8>::new());
393 /// br.init();
394 /// for idx in 0..8 {
395 /// let c = br.clone();
396 /// let _ = thd::spawn(move |_| { // 子线程闭包
397 /// c.wait_to(xwtm::ft(xwtm::s(3)));
398 /// });
399 /// }
400 /// }
401 /// ```
402 pub fn wait_to(&self, to: XwTm) -> BrError {
403 unsafe {
404 let mut rc = xwrustffi_br_acquire(self.br.get() as _, *self.tik.get());
405 if rc == 0 {
406 rc = xwrustffi_br_wait_to(self.br.get() as _, to);
407 xwrustffi_br_put(self.br.get() as _);
408 if XWOK == rc {
409 BrError::Ok(rc)
410 } else if -ECHRNG == rc {
411 BrError::OutOfRange(rc)
412 } else if -EINTR == rc {
413 BrError::Interrupt(rc)
414 } else if -ETIMEDOUT == rc {
415 BrError::Timedout(rc)
416 } else if -ENOTTHDCTX == rc {
417 BrError::NotThreadContext(rc)
418 } else {
419 BrError::Unknown(rc)
420 }
421 } else {
422 BrError::NotInit(rc)
423 }
424 }
425 }
426
427 /// 绑定线程栅栏对象到信号选择器
428 ///
429 /// + 线程栅栏绑定到信号选择器上时,采用 **非独占** 的方式进行绑定。
430 /// + 绑定成功,通过 [`Ok()`] 返回 [`BrSel<'a, N, M>`] 。
431 /// + 如果位置已被其他 **同步对象** 以 **独占** 的方式占领,通过 [`Err()`] 返回 [`BrError::SelPosBusy`] 。
432 /// + 当指定的位置超出范围(例如 [`Sel<M>`] 只有8个位置,用户偏偏要绑定到位置9 ),通过 [`Err()`] 返回 [`BrError::OutOfSelPos`] 。
433 /// + 重复绑定,通过 [`Err()`] 返回 [`BrError::AlreadyBound`] 。
434 ///
435 /// [`BrSel<'a, N, M>`] 中包含线程栅栏的绑定信息。 [`BrSel<'a, N, M>`] 与 [`Br<N>`] 与 [`Sel<M>`] 具有相同的生命周期约束 `'a` 。
436 /// [`BrSel::selected()`] 可用来判断线程栅栏是否被选择。当 [`BrSel<'a, N, M>`] [`drop()`] 时,会自动解绑。
437 ///
438 /// # 参数说明
439 ///
440 /// + sel: 信号选择器的引用
441 /// + pos: 位置
442 ///
443 /// # 上下文
444 ///
445 /// + 任意
446 ///
447 /// # 错误码
448 ///
449 /// + [`BrError::OutOfSelPos`] 信号选择器的位置超出范围
450 /// + [`BrError::AlreadyBound`] 线程栅栏已经绑定
451 /// + [`BrError::SelPosBusy`] 信号选择器的位置被占用
452 ///
453 /// # 示例
454 ///
455 /// ```rust
456 /// pub fn xwrust_example_sel() {
457 /// // ...省略...
458 /// let br0 = Arc::new(Br::new());
459 /// br0.init();
460 /// let br0sel = match br0.bind(&sel, 0) {
461 /// Ok(s) => { // 绑定成功,`s` 为 `BrSel`
462 /// s
463 /// },
464 /// Err(e) => { // 绑定失败,`e` 为 `SelError`
465 /// return;
466 /// }
467 /// };
468 /// // ...省略...
469 /// }
470 /// ```
471 ///
472 /// [`BrSel<'a, N, M>`]: BrSel
473 /// [`Ok()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Ok>
474 /// [`Err()`]: <https://doc.rust-lang.org/core/result/enum.Result.html#variant.Err>
475 /// [`Sel<M>`]: super::sel::Sel
476 /// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
477 pub fn bind<'a, const M: XwSz>(&'a self, sel: &'a Sel<M>, pos: XwSq) ->
478 Result<BrSel<'a, N, M>, BrError>
479 where
480 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
481 {
482 unsafe {
483 let mut rc = xwrustffi_br_acquire(self.br.get() as _, *self.tik.get());
484 if rc == 0 {
485 rc = xwrustffi_br_bind(self.br.get() as _, sel.sel.get() as _, pos);
486 if XWOK == rc {
487 Ok(BrSel {
488 br: self,
489 sel: sel,
490 pos: pos,
491 })
492 } else if -ECHRNG == rc {
493 Err(BrError::OutOfSelPos(rc))
494 } else if -EALREADY == rc {
495 Err(BrError::AlreadyBound(rc))
496 } else if -EBUSY == rc {
497 Err(BrError::SelPosBusy(rc))
498 } else {
499 Err(BrError::Unknown(rc))
500 }
501 } else {
502 Err(BrError::NotInit(rc))
503 }
504 }
505 }
506}
507
508/// 线程栅栏的选择子
509///
510/// `BrSel<'a, N, M>` 与 [`Br<N>`] 与 [`Sel<M>`] 具有相同的生命周期约束 `'a` 。因为 `BrSel<'a, N, M>` 中包含了 [`Br<N>`] 与 [`Sel<M>`] 的引用。
511///
512/// `BrSel<'a, N, M>` 中包含了绑定的位置信息,线程栅栏采用 **非独占** 的方式进行绑定。
513///
514/// [`BrSel::selected()`] 可用来判断线程栅栏是否被选择。
515///
516/// 当 `BrSel<'a, N, M>` 被 [`drop()`] 时,会自动将 [`Br<N>`] 从 [`Sel<M>`] 解绑。
517///
518/// [`Sel<M>`]: super::sel::Sel
519/// [`drop()`]: https://doc.rust-lang.org/std/mem/fn.drop.html
520pub struct BrSel<'a, const N: XwSz, const M: XwSz>
521where
522 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
523 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
524{
525 /// 线程栅栏
526 pub br: &'a Br<N>,
527 /// 信号选择器
528 pub sel: &'a Sel<M>,
529 /// 位置
530 pub pos: XwSq,
531}
532
533unsafe impl<'a, const N: XwSz, const M: XwSz> Send for BrSel<'a, N, M>
534where
535 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
536 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
537{}
538
539unsafe impl<'a, const N: XwSz, const M: XwSz> Sync for BrSel<'a, N, M>
540where
541 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
542 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
543{}
544
545impl<'a, const N: XwSz, const M: XwSz> Drop for BrSel<'a, N, M>
546where
547 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
548 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
549{
550 fn drop(&mut self) {
551 unsafe {
552 xwrustffi_br_unbind(self.br.br.get() as _, self.br.br.get() as _);
553 xwrustffi_br_put(self.br.br.get() as _);
554 }
555 }
556}
557
558impl<'a, const N: XwSz, const M: XwSz> BrSel<'a, N, M>
559where
560 [XwBmp; (N + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized,
561 [XwBmp; (M + XwBmp::BITS as usize - 1) / XwBmp::BITS as usize]: Sized
562{
563 /// 判断触发的 **选择信号** 是否包括此线程栅栏
564 ///
565 /// # 示例
566 ///
567 /// ```rust
568 /// let msk = Bmp::<8>::new(); // 8位位图
569 /// msk.s1all(); // 掩码为0xFF
570 /// loop {
571 /// let res = sel.select(&msk);
572 /// match res {
573 /// Ok(t) => { // 信号选择器上有 **选择信号** , `t` 为 **选择信号** 的位图。
574 /// if br0sel.selected(&t) { // 线程栅栏被选择到
575 /// }
576 /// },
577 /// Err(e) => { // 等待信号选择器失败,`e` 为 `SelError`
578 /// break;
579 /// },
580 /// }
581 /// }
582 /// ```
583 pub fn selected(&self, trg: &Bmp<M>) -> bool {
584 trg.t1i(self.pos)
585 }
586}