rt/rust/src/sync/barrier.rs

73 lines
1.7 KiB
Rust

use core::{
cell::UnsafeCell,
marker::PhantomPinned,
panic::{RefUnwindSafe, UnwindSafe},
};
use crate::{
bindings::{rt_barrier, rt_barrier_wait, rt_cond, rt_mutex},
list::list_init,
sync::semaphore::c_sem_init,
};
pub struct Barrier {
b: UnsafeCell<rt_barrier>,
_pin_marker: PhantomPinned,
}
unsafe impl Send for Barrier {}
unsafe impl Sync for Barrier {}
impl UnwindSafe for Barrier {}
impl RefUnwindSafe for Barrier {}
pub struct BarrierWaitResult(bool);
impl Barrier {
pub const fn init(barrier: &'static Barrier, count: u32) -> Barrier {
let b = unsafe { &*(barrier.b.get() as *const rt_barrier) };
Barrier {
b: UnsafeCell::new(rt_barrier {
mutex: rt_mutex {
holder: 0,
wait_list: list_init(&b.mutex.wait_list),
list: list_init(&b.mutex.list),
},
cond: rt_cond {
sem: c_sem_init(&b.cond.sem, 0, 0),
},
level: 0,
threshold: count,
generation: 0,
}),
_pin_marker: PhantomPinned,
}
}
pub fn wait(&self) -> BarrierWaitResult {
BarrierWaitResult(unsafe { rt_barrier_wait(self.b.get()) })
}
}
impl BarrierWaitResult {
#[must_use]
pub fn is_leader(&self) -> bool {
self.0
}
}
#[macro_export]
macro_rules! barrier {
($name: ident, $count: expr) => {
static $name: $crate::sync::Barrier = $crate::sync::Barrier::init(&$name, $count);
};
}
#[cfg(test)]
mod tests {
#[test]
fn fast_path() {
barrier!(BARRIER, 1);
assert!(BARRIER.wait().is_leader());
}
}