use std::cell::UnsafeCell;
use std::ptr::{read_volatile, write_volatile};
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use crate::events::TransportInfo;
pub struct TransportSlot {
seq: AtomicU64,
data: UnsafeCell<TransportInfo>,
}
unsafe impl Sync for TransportSlot {}
unsafe impl Send for TransportSlot {}
impl TransportSlot {
#[must_use]
pub fn new() -> Arc<Self> {
Arc::new(Self {
seq: AtomicU64::new(0),
data: UnsafeCell::new(TransportInfo::default()),
})
}
pub fn write(&self, info: &TransportInfo) {
let s = self.seq.load(Ordering::Relaxed);
self.seq.store(s.wrapping_add(1), Ordering::Relaxed);
unsafe {
write_volatile(self.data.get(), *info);
}
self.seq.store(s.wrapping_add(2), Ordering::Release);
}
pub fn read(&self) -> Option<TransportInfo> {
for _ in 0..8 {
let s1 = self.seq.load(Ordering::Acquire);
if s1 == 0 {
return None;
}
if s1 & 1 == 1 {
std::hint::spin_loop();
continue;
}
let snapshot = unsafe { read_volatile(self.data.get()) };
let s2 = self.seq.load(Ordering::Acquire);
if s1 == s2 {
return Some(snapshot);
}
}
None
}
}