cfg_if::cfg_if! {
if #[cfg(target_os = "windows")] {
mod windows;
use windows as os;
} else if #[cfg(target_family = "unix")] {
mod unix;
use unix as os;
} else {
unimplemented!("This crate does not support your OS yet !");
}
}
use crate::{Result, Timeout};
pub use os::*;
pub enum EventState {
Clear,
Signaled,
}
pub trait EventInit {
fn size_of(addr: Option<*mut u8>) -> usize;
unsafe fn new(mem: *mut u8, auto_reset: bool) -> Result<(Box<dyn EventImpl>, usize)>;
unsafe fn from_existing(mem: *mut u8) -> Result<(Box<dyn EventImpl>, usize)>;
}
pub trait EventImpl {
fn wait(&self, timeout: Timeout) -> Result<()>;
fn set(&self, state: EventState) -> Result<()>;
}
use std::mem::size_of;
use std::sync::atomic::{AtomicU8, Ordering};
use std::time;
struct InnerBusy {
signal: AtomicU8,
auto_reset: u8,
}
pub struct BusyEvent {
inner: *mut InnerBusy,
}
impl EventInit for BusyEvent {
fn size_of(_addr: Option<*mut u8>) -> usize {
size_of::<InnerBusy>()
}
#[allow(clippy::new_ret_no_self)]
unsafe fn new(mem: *mut u8, auto_reset: bool) -> Result<(Box<dyn EventImpl>, usize)> {
let ptr = mem as *mut InnerBusy;
let obj = Self { inner: ptr };
let inner = &mut *obj.inner;
inner.auto_reset = if auto_reset { 1 } else { 0 };
obj.set(EventState::Clear)?;
Ok((Box::new(obj), Self::size_of(None)))
}
unsafe fn from_existing(mem: *mut u8) -> Result<(Box<dyn EventImpl>, usize)> {
let ptr = mem as *mut InnerBusy;
let obj = Self { inner: ptr };
let inner = &mut *obj.inner;
if inner.auto_reset > 1 || inner.signal.load(Ordering::Relaxed) > 1 {
return Err(From::from("Existing BusyEvent is corrupted"));
}
Ok((Box::new(obj), Self::size_of(None)))
}
}
fn busy_wait_auto(signal: &mut AtomicU8, timeout: Timeout) -> Result<()> {
let mut prev_val = signal.compare_and_swap(1, 0, Ordering::Relaxed);
if prev_val == 1 {
return Ok(());
}
match timeout {
Timeout::Infinite => {
while prev_val == 0 {
prev_val = signal.compare_and_swap(1, 0, Ordering::Relaxed);
}
}
Timeout::Val(d) => {
let start = time::Instant::now();
while prev_val == 0 && start.elapsed() < d {
prev_val = signal.compare_and_swap(1, 0, Ordering::Relaxed);
}
}
};
if prev_val == 1 {
Ok(())
} else {
Err(From::from("Waiting for BusyEvent timed out !".to_string()))
}
}
fn busy_wait_manual(signal: &mut AtomicU8, timeout: Timeout) -> Result<()> {
let mut prev_val = signal.load(Ordering::Relaxed);
if prev_val == 1 {
return Ok(());
}
match timeout {
Timeout::Infinite => {
while prev_val == 0 {
prev_val = signal.load(Ordering::Relaxed);
}
}
Timeout::Val(d) => {
let start = time::Instant::now();
while prev_val == 0 && start.elapsed() < d {
prev_val = signal.load(Ordering::Relaxed);
}
}
};
if prev_val == 1 {
Ok(())
} else {
Err(From::from("Waiting for BusyEvent timed out !".to_string()))
}
}
impl EventImpl for BusyEvent {
fn wait(&self, timeout: Timeout) -> Result<()> {
let inner = unsafe { &mut *self.inner };
if inner.auto_reset == 1 {
busy_wait_auto(&mut inner.signal, timeout)
} else {
busy_wait_manual(&mut inner.signal, timeout)
}
}
fn set(&self, state: EventState) -> Result<()> {
let inner = unsafe { &mut *self.inner };
match state {
EventState::Clear => {
inner.signal.store(0, Ordering::Relaxed);
}
EventState::Signaled => {
inner.signal.store(1, Ordering::Relaxed);
}
};
Ok(())
}
}