use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
use std::sync::OnceLock;
use super::{Ring, RingConfig, Sqe};
pub(crate) fn flag_works() -> bool {
static WORKS: OnceLock<bool> = OnceLock::new();
*WORKS.get_or_init(|| trial().unwrap_or(false))
}
fn trial() -> std::io::Result<bool> {
let wake = unsafe {
let fd = libc::eventfd(0, libc::EFD_CLOEXEC);
if fd < 0 {
return Err(std::io::Error::last_os_error());
}
OwnedFd::from_raw_fd(fd)
};
let mut ring = Ring::new(&RingConfig {
taskrun_flag: true,
..RingConfig::new(4)
})?;
let mut buf = Box::new(0u64);
let read = Sqe::read(
wake.as_raw_fd(),
core::ptr::from_mut(&mut *buf).cast(),
8,
0,
)
.user_data(1);
ring.push(&read)
.map_err(|_| std::io::Error::other("no room in a new ring"))?;
ring.submit()?;
if ring.taskrun_pending() {
return Ok(false);
}
unsafe { libc::write(wake.as_raw_fd(), 1u64.to_ne_bytes().as_ptr().cast(), 8) };
let deadline = std::time::Instant::now() + std::time::Duration::from_millis(50);
let flagged = loop {
if ring.taskrun_pending() {
break true;
}
if std::time::Instant::now() >= deadline {
break false;
}
std::thread::yield_now();
};
ring.submit_and_wait(1, Some(std::time::Duration::from_millis(100)))?;
let done = ring.completions().any(|cqe| cqe.user_data == 1);
Ok(flagged && done)
}