Skip to main content

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}