Skip to main content

dope_core/
driver.rs

1use std::future::Future;
2use std::io;
3use std::time::Duration;
4
5use crate::addr::SockAddr;
6use crate::submit::SendMsgPacket;
7use crate::{Fd, FixedFd};
8
9pub trait RecvMsgOutView {
10    fn parse_with<R>(
11        raw: &[u8],
12        msghdr: &libc::msghdr,
13        f: impl FnOnce(&[u8], &[u8]) -> R,
14    ) -> Option<R>;
15}
16
17pub trait DriverLifecycle {
18    fn drive(&mut self) -> io::Result<bool>;
19    fn has_pending(&mut self) -> bool;
20    fn park(&mut self) -> io::Result<()>;
21    fn park_for(&mut self, duration: Duration) -> io::Result<()>;
22    fn submit_only(&mut self) -> io::Result<()>;
23
24    #[inline]
25    fn arm_with_retry<F>(&mut self, mut op: F) -> bool
26    where
27        F: FnMut(&mut Self) -> bool,
28    {
29        if op(self) {
30            return true;
31        }
32        let _ = self.submit_only();
33        op(self)
34    }
35}
36
37pub trait FixedBuffers {
38    type Guard;
39    fn fixed_guard(&mut self) -> Option<Self::Guard>;
40    fn register_fixed(&mut self, fd: Fd) -> io::Result<Option<u32>>;
41    fn unregister_fixed(&mut self, idx: u32);
42}
43
44pub trait ProvidedBufRing {
45    type Provided: AsRef<[u8]> + 'static;
46    fn provided_group(&mut self) -> Option<(u16, u32)>;
47    fn provided(&mut self, bid: u16, len: usize) -> Option<Self::Provided>;
48}
49
50pub trait DriverConfig: Sized + Copy {
51    fn for_profile<P: crate::profile::Profile>() -> Self;
52
53    fn for_tcp_profile(ring_entries: u32, max_conn: usize, ingress_buf_cap: usize) -> Self;
54    fn for_quic_udp(provided_buf_entries: u32, provided_buf_len: u32) -> Self;
55
56    #[inline(always)]
57    fn with_defer_taskrun(self, _enable: bool) -> Self {
58        self
59    }
60
61    #[inline(always)]
62    fn with_cpu_id(self, _cpu: Option<u16>) -> Self {
63        self
64    }
65}
66
67pub trait Backend: Sized {
68    type Driver: DriverLifecycle + FixedBuffers + ProvidedBufRing + 'static;
69    type Config: DriverConfig;
70    type RecvMsgOut: RecvMsgOutView;
71    type ProvidedBuf;
72
73    fn new_driver(cfg: Self::Config) -> io::Result<Self::Driver>;
74}
75
76pub trait BackendToken: Copy + 'static {
77    fn parts(self) -> (usize, u32);
78    fn next_for_slot(index: usize, seq: &mut u32) -> Self;
79    fn from_index_raw(index: usize, epoch: u32) -> Self;
80}
81
82pub enum Completion<B: CompletionBackend> {
83    Accept {
84        token: B::Token,
85        result: i32,
86        more: bool,
87    },
88    Recv {
89        token: B::Token,
90        result: i32,
91        more: bool,
92        bid: Option<u16>,
93    },
94    Write {
95        token: B::Token,
96        result: i32,
97        notif: bool,
98    },
99}
100
101impl<B: CompletionBackend> Completion<B> {
102    #[inline(always)]
103    pub fn buffer_select(&self) -> Option<u16> {
104        match self {
105            Self::Recv { bid, .. } => *bid,
106            _ => None,
107        }
108    }
109}
110
111pub struct CurrentSlot<B: CompletionBackend> {
112    driver: std::ptr::NonNull<B::Driver>,
113    extra: *const (),
114}
115
116impl<B: CompletionBackend> Clone for CurrentSlot<B> {
117    fn clone(&self) -> Self {
118        *self
119    }
120}
121
122impl<B: CompletionBackend> Copy for CurrentSlot<B> {}
123
124impl<B: CompletionBackend> CurrentSlot<B> {
125    #[inline(always)]
126    pub fn new(driver: std::ptr::NonNull<B::Driver>, extra: *const ()) -> Self {
127        Self { driver, extra }
128    }
129
130    #[inline(always)]
131    pub fn driver(self) -> std::ptr::NonNull<B::Driver> {
132        self.driver
133    }
134
135    #[inline(always)]
136    pub fn extra(self) -> *const () {
137        self.extra
138    }
139}
140
141pub struct ExternalDispatch<B: CompletionBackend> {
142    pub state: *mut (),
143    pub route: unsafe fn(*mut (), &mut B::Driver, Completion<B>),
144    pub pump: unsafe fn(*mut (), &mut B::Driver),
145}
146
147impl<B: CompletionBackend> Clone for ExternalDispatch<B> {
148    fn clone(&self) -> Self {
149        *self
150    }
151}
152
153impl<B: CompletionBackend> Copy for ExternalDispatch<B> {}
154
155pub trait CompletionBackend: Backend {
156    type Token: BackendToken;
157
158    fn current_slot() -> Option<CurrentSlot<Self>>;
159    fn set_slot(slot: Option<CurrentSlot<Self>>);
160
161    #[inline(always)]
162    fn current_driver_mut() -> *mut Self::Driver {
163        match Self::current_slot() {
164            Some(slot) => slot.driver().as_ptr(),
165            None => std::ptr::null_mut(),
166        }
167    }
168
169    #[inline(always)]
170    fn set_current(driver: *mut Self::Driver) {
171        let slot = std::ptr::NonNull::new(driver).map(|d| CurrentSlot::new(d, std::ptr::null()));
172        Self::set_slot(slot);
173    }
174
175    #[inline(always)]
176    fn clear_current() {
177        Self::set_slot(None);
178    }
179
180    fn install_external(aux: Option<ExternalDispatch<Self>>) -> Option<ExternalDispatch<Self>>;
181    fn current_external() -> Option<ExternalDispatch<Self>>;
182
183    fn drive_with<R: CompletionRouter<Self>>(
184        driver: &mut Self::Driver,
185        router: &mut R,
186    ) -> io::Result<bool>;
187
188    fn dispatch_completions<R: CompletionRouter<Self>>(driver: &mut Self::Driver, router: &mut R);
189}
190
191pub trait CompletionRouter<B: CompletionBackend> {
192    fn on_complete(&mut self, driver: &mut B::Driver, ev: Completion<B>);
193}
194
195pub trait ProvidedRingOps {
196    fn defer(&mut self, bid: u16);
197    fn ptr_len(&self, bid: u16) -> (*mut u8, usize);
198}
199
200pub trait DriverOps: 'static {
201    type Token: BackendToken;
202    type ProvidedRing: ProvidedRingOps + 'static;
203    type IoRequest<O: Unpin + 'static>: Future<Output = (io::Result<u32>, u32, O)> + Unpin + 'static;
204
205    fn buf_group(&self) -> u16;
206    fn provided_ring(&mut self) -> &mut Self::ProvidedRing;
207
208    fn arm_accept_multi(&mut self, token: Self::Token, fd: Fd) -> bool;
209    fn arm_recv_multi(&mut self, token: Self::Token, fd: FixedFd, buf_group: u16) -> bool;
210
211    /// # Safety
212    /// `msghdr` must remain valid until the multishot recv is cancelled.
213    unsafe fn arm_recv_msg_multi(
214        &mut self,
215        token: Self::Token,
216        fd: FixedFd,
217        buf_group: u16,
218        msghdr: *const libc::msghdr,
219    ) -> bool;
220
221    fn submit_send_tagged(
222        &mut self,
223        token: Self::Token,
224        fd: FixedFd,
225        ptr: *const u8,
226        len: u32,
227    ) -> bool;
228
229    /// # Safety
230    /// `msg` must remain valid until the submission completes.
231    unsafe fn submit_send_msg_tagged(
232        &mut self,
233        token: Self::Token,
234        fd: FixedFd,
235        msg: *const libc::msghdr,
236    ) -> bool;
237
238    fn cancel_recv(&mut self, token: Self::Token);
239
240    fn try_submit_connect_raw(
241        &mut self,
242        fd: Fd,
243        addr: SockAddr,
244    ) -> Result<Self::IoRequest<SockAddr>, (io::Error, SockAddr)>;
245
246    fn try_submit_sendmsg_raw<P: SendMsgPacket + Unpin + 'static>(
247        &mut self,
248        fd: Fd,
249        packet: P,
250    ) -> Result<Self::IoRequest<P>, (io::Error, P)>;
251
252    fn try_submit_send_raw<B: AsRef<[u8]> + Unpin + 'static>(
253        &mut self,
254        fd: Fd,
255        buf: B,
256    ) -> Result<Self::IoRequest<B>, (io::Error, B)>;
257}
258
259pub trait PoolDriver:
260    CompletionBackend<Driver: DriverOps<Token = <Self as CompletionBackend>::Token>> + 'static
261{
262}
263
264impl<B> PoolDriver for B
265where
266    B: CompletionBackend + 'static,
267    B::Driver: DriverOps<Token = B::Token>,
268{
269}
270
271pub type IoRequest<B, O> = <<B as Backend>::Driver as DriverOps>::IoRequest<O>;
272pub type ProvidedRing<B> = <<B as Backend>::Driver as DriverOps>::ProvidedRing;