use core::{
cell::UnsafeCell,
panic::{RefUnwindSafe, UnwindSafe},
};
use crate::{
bindings::{rt_barrier, rt_barrier_wait, rt_mutex},
list::list_init,
ptr_macros::{ptr_to_field, ptr_to_field_mut},
sync::condvar::c_cond_init,
};
#[repr(transparent)]
pub struct Barrier {
barrier: UnsafeCell<rt_barrier>,
}
unsafe impl Send for Barrier {}
unsafe impl Sync for Barrier {}
impl UnwindSafe for Barrier {}
impl RefUnwindSafe for Barrier {}
pub struct BarrierWaitResult(bool);
impl Barrier {
#[must_use]
pub const unsafe fn init(this: *const Self, count: u32) -> Barrier {
let barrier = UnsafeCell::raw_get(ptr_to_field!(this, barrier));
Barrier {
barrier: UnsafeCell::new(rt_barrier {
mutex: rt_mutex {
holder: 0,
wait_list: list_init(ptr_to_field_mut!(barrier, mutex, wait_list)),
list: list_init(ptr_to_field_mut!(barrier, mutex, list)),
level: -1,
},
cond: c_cond_init(ptr_to_field_mut!(barrier, cond)),
level: 0,
threshold: count,
generation: 0,
}),
}
}
#[inline]
pub fn wait(&self) -> BarrierWaitResult {
BarrierWaitResult(unsafe { rt_barrier_wait(self.barrier.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 = {
let ptr = &raw const $name;
let count = $count;
unsafe { $crate::sync::Barrier::init(ptr, count) }
};
};
}
#[cfg(test)]
mod tests {
#[test]
fn fast_path() {
barrier!(BARRIER, 1);
assert!(BARRIER.wait().is_leader());
}
}