use std::io;
use std::sync::Mutex;
use std::sync::mpsc;
use std::time::Duration;
use durable_ioring::{DurableRing, EntryOf};
use win_sync_sys::Event;
use windows_threadpool_sys::wait::ThreadpoolWait;
#[cfg(test)]
mod tests;
#[derive(Debug)]
pub enum ReadinessFailure {
NotSetForFirstEntry,
NotSetAgain,
Io(io::Error),
}
impl From<io::Error> for ReadinessFailure {
fn from(error: io::Error) -> Self {
Self::Io(error)
}
}
pub fn check_readiness<D, P>(
ring: &mut D,
mut push: P,
bound: Duration,
) -> Result<Vec<EntryOf<D>>, ReadinessFailure>
where
D: DurableRing<Readiness = Event>,
P: FnMut(&mut D),
{
let mut entries = Vec::new();
let signal = ring.readiness()?;
drain(ring, &mut entries)?;
signal.reset()?;
let (woken, wakes) = mpsc::channel();
let woken = Mutex::new(woken);
let wait = ThreadpoolWait::new(
signal.into(),
move |_| {
if let Ok(woken) = woken.lock() {
let _ = woken.send(());
}
},
None,
)?;
let mut steps = || -> Result<(), ReadinessFailure> {
wait.arm(None);
push(ring);
wakes
.recv_timeout(bound)
.map_err(|_| ReadinessFailure::NotSetForFirstEntry)?;
drain(ring, &mut entries)?;
wait.arm(None);
push(ring);
wakes
.recv_timeout(bound)
.map_err(|_| ReadinessFailure::NotSetAgain)?;
drain(ring, &mut entries)?;
Ok(())
};
let outcome = steps();
wait.stop_and_drain();
outcome.map(|()| entries)
}
fn drain<D: DurableRing>(ring: &mut D, into: &mut Vec<EntryOf<D>>) -> io::Result<()> {
while let Some(entry) = ring.pop()? {
into.push(entry);
}
Ok(())
}