uring-async/src/op.rs
2026-09-28 23:22:04 +10:00

103 lines
3.0 KiB
Rust

use std::{
mem,
ops::DerefMut as _,
pin::Pin,
rc::Rc,
task::{Context, LocalWaker, Poll},
};
use io_uring::opcode::Nop;
use log::trace;
use unchecked_refcell::UncheckedRefCell;
use crate::{RT, Runtime, RuntimeInner, op::NoOp::Cancelled};
pub struct OpEntry(Rc<UncheckedRefCell<Op>>);
pub enum Op {
NoOp(NoOp),
}
enum NoOp {
New,
Live(LocalWaker),
Done,
Cancelled,
}
pub fn no_op() -> OpEntry {
OpEntry(Rc::new(UncheckedRefCell::new(Op::NoOp(NoOp::New))))
}
impl Future for OpEntry {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut lock = self.0.borrow_mut();
match &mut *lock {
Op::NoOp(NoOp::Cancelled) => unreachable!(),
Op::NoOp(NoOp::Done) => Poll::Ready(()),
Op::NoOp(op @ NoOp::New) => {
{
let rt: &Runtime = cx.ext().downcast_ref().unwrap();
let mut lock = rt.0.borrow_mut();
let mut sq = lock.ring.submission();
let entry = Nop::new().build().user_data(
Rc::into_raw(self.0.clone())
.expose_provenance()
.try_into()
.unwrap(),
);
trace!("Pushing SQE {:?}", &entry);
unsafe { sq.push(&entry) }.expect("failed to submit no-op");
}
*op = NoOp::Live(cx.local_waker().clone());
Poll::Pending
}
Op::NoOp(NoOp::Live(waker)) => {
waker.clone_from(cx.local_waker());
Poll::Pending
}
}
}
}
impl Op {
pub fn handle(this: Rc<UncheckedRefCell<Self>>) {
// TODO don't drop for multishot accepts
let mut lock = this.borrow_mut();
match lock.deref_mut() {
Op::NoOp(op) => match mem::replace(op, NoOp::Done) {
NoOp::New | NoOp::Done => unreachable!(),
NoOp::Cancelled => {}
NoOp::Live(waker) => waker.wake(),
},
}
}
}
/*
impl Drop for OpEntry {
fn drop(&mut self) {
let mut lock = self.0.borrow_mut();
match lock.deref_mut() {
Op::NoOp(op) => {
match mem::replace(op, NoOp::Cancelled) {
NoOp::New | NoOp::Done => {}
NoOp::Cancelled => unreachable!(),
NoOp::Live(_) => {
RT.with(|rt| {
let outer = rt.borrow();
let mut lock = outer.as_ref().expect("future cancelled outside runtime thread").0.borrow_mut();
let mut sq = lock.ring.submission();
let entry = AsyncCancel::new(self.0.as_ptr().addr().try_into().unwrap()).build();
todo!()
})
}
}
}
}
}
}
*/