use std::sync::{
Arc,
atomic::{AtomicU32, Ordering},
};
use std::task::{Wake, Waker};
use crate::metrics::Counters;
pub(crate) const RUNNING: u32 = 0;
pub(crate) const NOTIFIED: u32 = 1;
pub(crate) const PARKED: u32 = 2;
pub(crate) const FUTEX2_SIZE_U32: u32 = 0x2;
pub(crate) const FUTEX2_PRIVATE: u32 = 128;
pub(crate) const FUTEX_BITSET_MATCH_ANY: u64 = u32::MAX as u64;
pub(crate) struct Unpark {
pub(crate) word: AtomicU32,
metrics: Arc<Counters>,
}
impl Unpark {
pub(crate) fn new(metrics: Arc<Counters>) -> Arc<Self> {
Arc::new(Self {
word: AtomicU32::new(RUNNING),
metrics,
})
}
pub(crate) fn unpark(&self) {
if self.word.swap(NOTIFIED, Ordering::AcqRel) == PARKED {
self.metrics.wakes.add(1);
unsafe {
libc::syscall(
libc::SYS_futex,
self.word.as_ptr(),
libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG,
i32::MAX,
);
}
}
}
pub(crate) fn waker(self: &Arc<Self>) -> Waker {
Waker::from(self.clone())
}
}
impl Wake for Unpark {
fn wake(self: Arc<Self>) {
self.unpark();
}
fn wake_by_ref(self: &Arc<Self>) {
self.unpark();
}
}