Skip to main content

dope_uring/driver/request/
mod.rs

1mod small_slot;
2mod table;
3
4use std::{
5    io,
6    task::{Context, Poll},
7};
8
9use crate::sys::token::Completion;
10
11use super::Driver;
12use super::current::current_driver_mut;
13pub(crate) use table::Requests;
14
15#[repr(C, packed)]
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub(crate) struct RequestId {
18    index: u16,
19    epoch: u32,
20    _wire_pad: u8,
21}
22
23impl RequestId {
24    pub(crate) const EPOCH_MASK: u32 = 0x00ff_ffff;
25
26    pub(crate) fn new(index: usize, epoch: u32) -> Self {
27        Self {
28            index: u16::try_from(index)
29                .expect("dope invariant violated: request index exceeds u16 range"),
30            epoch: epoch & Self::EPOCH_MASK,
31            _wire_pad: 0,
32        }
33    }
34
35    pub(in crate::driver) fn index(self) -> usize {
36        self.index as usize
37    }
38
39    pub(in crate::driver) fn epoch(self) -> u32 {
40        self.epoch
41    }
42}
43
44enum RequestState<T> {
45    Pending { data: Box<T>, ticket: RequestTicket },
46    Done,
47}
48
49struct RequestTicket {
50    index: RequestId,
51}
52
53impl RequestTicket {
54    fn new(index: RequestId) -> Self {
55        Self { index }
56    }
57
58    fn poll(&self, cx: &mut Context<'_>) -> Poll<Completion> {
59        current_driver_mut().requests.poll(self.index, cx)
60    }
61
62    fn discard<T: 'static>(&self, data: &mut Option<T>) {
63        current_driver_mut().requests.discard(self.index, data);
64    }
65}
66
67pub struct Request<T: 'static> {
68    state: RequestState<T>,
69}
70
71impl<T: 'static> Request<T> {
72    pub(crate) fn submit_boxed(
73        ctx: &mut Driver,
74        data: Box<T>,
75        sqe: crate::Sqe,
76    ) -> Result<Self, (io::Error, Box<T>)> {
77        match ctx.submit_sqe_op(sqe) {
78            Ok(index) => Ok(Self {
79                state: RequestState::Pending {
80                    data,
81                    ticket: RequestTicket::new(index),
82                },
83            }),
84            Err(e) => Err((e, data)),
85        }
86    }
87}
88
89impl<T: Unpin + 'static> Request<T> {
90    pub(crate) async fn await_submit(submit: Result<Self, (io::Error, T)>) -> (io::Result<u32>, T) {
91        match submit {
92            Ok(req) => {
93                let (res, _, op) = req.await;
94                (res, op)
95            }
96            Err((e, op)) => (Err(e), op),
97        }
98    }
99}
100
101impl<T: Unpin + 'static> std::future::Future for Request<T> {
102    type Output = (io::Result<u32>, u32, T);
103
104    fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
105        let me = self.get_mut();
106        match &me.state {
107            RequestState::Pending { .. } => {}
108            RequestState::Done => panic!("dope invariant violated: polled completed request"),
109        }
110        let RequestState::Pending { ticket, .. } = &me.state else {
111            panic!("dope invariant violated: request poll state mismatch");
112        };
113        match ticket.poll(cx) {
114            Poll::Pending => Poll::Pending,
115            Poll::Ready(meta) => {
116                let RequestState::Pending { data, .. } =
117                    std::mem::replace(&mut me.state, RequestState::Done)
118                else {
119                    panic!("dope invariant violated: request completion state mismatch");
120                };
121                Poll::Ready((meta.result, meta.flags, *data))
122            }
123        }
124    }
125}
126
127impl<T: 'static> Drop for Request<T> {
128    fn drop(&mut self) {
129        let (ticket, data) = match std::mem::replace(&mut self.state, RequestState::Done) {
130            RequestState::Pending { ticket, data } => (ticket, data),
131            RequestState::Done => return,
132        };
133        let mut data = Some(*data);
134        ticket.discard(&mut data);
135    }
136}