use core::{
cell::UnsafeCell,
mem::zeroed,
panic::{RefUnwindSafe, UnwindSafe},
ptr::null_mut,
};
use crate::{
bindings::{
RT_EVENT_WAIT_ALL, RT_EVENT_WAIT_NOCLEAR, RT_EVENT_WAIT_RESERVED, rt_event, rt_event_clear,
rt_event_get, rt_event_set, rt_event_timedwait, rt_event_trywait, rt_event_wait,
rt_syscall_args, rt_syscall_args_event_set, rt_syscall_pendable, rt_syscall_record,
},
list::list_init,
ptr_macros::{ptr_to_field, ptr_to_field_mut},
tick::Utick,
};
#[repr(transparent)]
pub struct Event {
event: UnsafeCell<rt_event>,
}
unsafe impl Send for Event {}
unsafe impl Sync for Event {}
impl UnwindSafe for Event {}
impl RefUnwindSafe for Event {}
impl Event {
#[must_use]
pub const unsafe fn init(this: *const Self) -> Event {
let event = UnsafeCell::raw_get(ptr_to_field!(this, event));
Event {
event: UnsafeCell::new(rt_event {
bits: 0u32,
wait_list: list_init(ptr_to_field_mut!(event, wait_list)),
set_record: rt_syscall_record {
next: null_mut(),
args: unsafe {
let mut x: rt_syscall_args = zeroed();
x.event_set = rt_syscall_args_event_set { event };
x
},
syscall: rt_syscall_pendable::RT_SYSCALL_PENDABLE_EVENT_SET,
pending: unsafe { zeroed() },
},
}),
}
}
#[inline]
pub fn clear(&self, bits: u32) -> u32 {
unsafe { rt_event_clear(self.event.get(), bits) }
}
#[inline]
pub fn get(&self) -> u32 {
unsafe { rt_event_get(self.event.get()) }
}
#[inline]
pub fn set(&self, bits: u32) -> u32 {
unsafe { rt_event_set(self.event.get(), bits) }
}
#[inline]
pub fn wait(&self, wait: u32) -> u32 {
unsafe { rt_event_wait(self.event.get(), wait) }
}
#[inline]
pub fn try_wait(&self, wait: u32) -> u32 {
unsafe { rt_event_trywait(self.event.get(), wait) }
}
#[inline]
pub fn timed_wait(&self, wait: u32, ticks: Utick) -> u32 {
unsafe { rt_event_timedwait(self.event.get(), wait, ticks) }
}
}
#[inline]
pub const fn bits_match(bits: u32, wait: u32) -> bool {
let waitbits = wait & !RT_EVENT_WAIT_RESERVED;
let bmatch = bits & waitbits;
if (wait & WAIT_ALL) != 0 {
return bmatch == waitbits;
}
bmatch != 0
}
pub const WAIT_ALL: u32 = RT_EVENT_WAIT_ALL;
pub const WAIT_NOCLEAR: u32 = RT_EVENT_WAIT_NOCLEAR;
#[macro_export]
macro_rules! event {
($name: ident) => {
static $name: $crate::sync::Event = {
let ptr = &raw const $name;
unsafe { $crate::sync::Event::init(ptr) }
};
};
}
#[cfg(test)]
mod tests {
#[test]
fn fast_path() {
event!(EVENT);
EVENT.set(1);
assert_eq!(EVENT.wait(1), 1);
assert_eq!(EVENT.try_wait(1), 0);
}
}