rt/rust/src/sync/notify.rs

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);
}
}