139 lines
3.2 KiB
Rust
139 lines
3.2 KiB
Rust
use core::{
|
|
cell::UnsafeCell,
|
|
marker::PhantomPinned,
|
|
panic::{RefUnwindSafe, UnwindSafe},
|
|
};
|
|
|
|
use crate::{
|
|
bindings::{
|
|
rt_notify, rt_notify_add, rt_notify_or, rt_notify_post, rt_notify_set, rt_notify_timedwait,
|
|
rt_notify_timedwait_clear, rt_notify_trywait, rt_notify_trywait_clear, rt_notify_wait,
|
|
rt_notify_wait_clear,
|
|
},
|
|
sync::semaphore::c_sem_init,
|
|
tick::Utick,
|
|
};
|
|
|
|
pub struct Notify {
|
|
n: UnsafeCell<rt_notify>,
|
|
_pin_marker: PhantomPinned,
|
|
}
|
|
|
|
unsafe impl Send for Notify {}
|
|
unsafe impl Sync for Notify {}
|
|
impl UnwindSafe for Notify {}
|
|
impl RefUnwindSafe for Notify {}
|
|
|
|
impl Notify {
|
|
pub const fn init(note: &'static Notify, value: u32) -> Notify {
|
|
let n = unsafe { &*(note.n.get() as *const rt_notify) };
|
|
Notify {
|
|
n: UnsafeCell::new(rt_notify {
|
|
value,
|
|
sem: c_sem_init(&n.sem, 0, 0),
|
|
}),
|
|
_pin_marker: PhantomPinned,
|
|
}
|
|
}
|
|
|
|
pub fn post(&self) {
|
|
unsafe { rt_notify_post(self.n.get()) }
|
|
}
|
|
|
|
pub fn or(&self, v: u32) {
|
|
unsafe { rt_notify_or(self.n.get(), v) }
|
|
}
|
|
|
|
pub fn add(&self, v: u32) {
|
|
unsafe { rt_notify_add(self.n.get(), v) }
|
|
}
|
|
|
|
pub fn set(&self, v: u32) {
|
|
unsafe { rt_notify_set(self.n.get(), v) }
|
|
}
|
|
|
|
pub fn wait(&self) -> u32 {
|
|
unsafe { rt_notify_wait(self.n.get()) }
|
|
}
|
|
|
|
pub fn wait_clear(&self, c: u32) -> u32 {
|
|
unsafe { rt_notify_wait_clear(self.n.get(), c) }
|
|
}
|
|
|
|
pub fn try_wait(&self) -> Option<u32> {
|
|
let mut v = 0;
|
|
if unsafe { rt_notify_trywait(self.n.get(), &mut v) } {
|
|
Some(v)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn try_wait_clear(&self, c: u32) -> Option<u32> {
|
|
let mut v = 0;
|
|
if unsafe { rt_notify_trywait_clear(self.n.get(), &mut v, c) } {
|
|
Some(v)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn timed_wait(&self, ticks: Utick) -> Option<u32> {
|
|
let mut v = 0;
|
|
if unsafe { rt_notify_timedwait(self.n.get(), &mut v, ticks) } {
|
|
Some(v)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn timed_wait_clear(&self, c: u32, ticks: Utick) -> Option<u32> {
|
|
let mut v = 0;
|
|
if unsafe { rt_notify_timedwait_clear(self.n.get(), &mut v, c, ticks) } {
|
|
Some(v)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! notify {
|
|
($name: ident, $value: expr) => {
|
|
static $name: $crate::sync::Notify = $crate::sync::Notify::init(&$name, $value);
|
|
};
|
|
|
|
($name: ident) => {
|
|
$crate::notify!($name, 0);
|
|
};
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
#[test]
|
|
fn fast_path() {
|
|
notify!(NOTIFY);
|
|
NOTIFY.post();
|
|
assert!(NOTIFY.wait() == 0);
|
|
}
|
|
|
|
#[test]
|
|
fn ops() {
|
|
notify!(NOTIFY);
|
|
NOTIFY.or(1);
|
|
assert!(NOTIFY.wait() == 1);
|
|
NOTIFY.add(1);
|
|
assert!(NOTIFY.wait() == 2);
|
|
NOTIFY.set(3);
|
|
assert!(NOTIFY.wait() == 3);
|
|
}
|
|
|
|
#[test]
|
|
fn clear() {
|
|
notify!(NOTIFY);
|
|
NOTIFY.or(u32::MAX);
|
|
assert!(NOTIFY.wait_clear(0xFF) == u32::MAX);
|
|
assert!(NOTIFY.wait() == 0xFFFFFF00);
|
|
}
|
|
}
|