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>); 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 { 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>) { // 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!() }) } } } } } } */