use std::future::Future;
use std::io;
use std::time::Duration;
use crate::addr::SockAddr;
use crate::submit::SendMsgPacket;
use crate::{Fd, FixedFd};
pub trait RecvMsgOutView {
fn parse_with<R>(
raw: &[u8],
msghdr: &libc::msghdr,
f: impl FnOnce(&[u8], &[u8]) -> R,
) -> Option<R>;
}
pub trait DriverLifecycle {
fn drive(&mut self) -> io::Result<bool>;
fn has_pending(&mut self) -> bool;
fn park(&mut self) -> io::Result<()>;
fn park_for(&mut self, duration: Duration) -> io::Result<()>;
fn submit_only(&mut self) -> io::Result<()>;
#[inline]
fn arm_with_retry<F>(&mut self, mut op: F) -> bool
where
F: FnMut(&mut Self) -> bool,
{
if op(self) {
return true;
}
let _ = self.submit_only();
op(self)
}
}
pub trait FixedBuffers {
type Guard;
fn fixed_guard(&mut self) -> Option<Self::Guard>;
fn register_fixed(&mut self, fd: Fd) -> io::Result<Option<u32>>;
fn unregister_fixed(&mut self, idx: u32);
}
pub trait ProvidedBufRing {
type Provided: AsRef<[u8]> + 'static;
fn provided_group(&mut self) -> Option<(u16, u32)>;
fn provided(&mut self, bid: u16, len: usize) -> Option<Self::Provided>;
}
pub trait DriverConfig: Sized + Copy {
fn for_profile<P: crate::profile::Profile>() -> Self;
fn for_tcp_profile(ring_entries: u32, max_conn: usize, ingress_buf_cap: usize) -> Self;
fn for_quic_udp(provided_buf_entries: u32, provided_buf_len: u32) -> Self;
#[inline(always)]
fn with_defer_taskrun(self, _enable: bool) -> Self {
self
}
#[inline(always)]
fn with_cpu_id(self, _cpu: Option<u16>) -> Self {
self
}
}
pub trait Backend: Sized {
type Driver: DriverLifecycle + FixedBuffers + ProvidedBufRing + 'static;
type Config: DriverConfig;
type RecvMsgOut: RecvMsgOutView;
type ProvidedBuf;
fn new_driver(cfg: Self::Config) -> io::Result<Self::Driver>;
}
pub trait BackendToken: Copy + 'static {
fn parts(self) -> (usize, u32);
fn next_for_slot(index: usize, seq: &mut u32) -> Self;
fn from_index_raw(index: usize, epoch: u32) -> Self;
}
pub enum Completion<B: CompletionBackend> {
Accept {
token: B::Token,
result: i32,
more: bool,
},
Recv {
token: B::Token,
result: i32,
more: bool,
bid: Option<u16>,
},
Write {
token: B::Token,
result: i32,
notif: bool,
},
}
impl<B: CompletionBackend> Completion<B> {
#[inline(always)]
pub fn buffer_select(&self) -> Option<u16> {
match self {
Self::Recv { bid, .. } => *bid,
_ => None,
}
}
}
pub struct CurrentSlot<B: CompletionBackend> {
driver: std::ptr::NonNull<B::Driver>,
extra: *const (),
}
impl<B: CompletionBackend> Clone for CurrentSlot<B> {
fn clone(&self) -> Self {
*self
}
}
impl<B: CompletionBackend> Copy for CurrentSlot<B> {}
impl<B: CompletionBackend> CurrentSlot<B> {
#[inline(always)]
pub fn new(driver: std::ptr::NonNull<B::Driver>, extra: *const ()) -> Self {
Self { driver, extra }
}
#[inline(always)]
pub fn driver(self) -> std::ptr::NonNull<B::Driver> {
self.driver
}
#[inline(always)]
pub fn extra(self) -> *const () {
self.extra
}
}
pub struct ExternalDispatch<B: CompletionBackend> {
pub state: *mut (),
pub route: unsafe fn(*mut (), &mut B::Driver, Completion<B>),
pub pump: unsafe fn(*mut (), &mut B::Driver),
}
impl<B: CompletionBackend> Clone for ExternalDispatch<B> {
fn clone(&self) -> Self {
*self
}
}
impl<B: CompletionBackend> Copy for ExternalDispatch<B> {}
pub trait CompletionBackend: Backend {
type Token: BackendToken;
fn current_slot() -> Option<CurrentSlot<Self>>;
fn set_slot(slot: Option<CurrentSlot<Self>>);
#[inline(always)]
fn current_driver_mut() -> *mut Self::Driver {
match Self::current_slot() {
Some(slot) => slot.driver().as_ptr(),
None => std::ptr::null_mut(),
}
}
#[inline(always)]
fn set_current(driver: *mut Self::Driver) {
let slot = std::ptr::NonNull::new(driver).map(|d| CurrentSlot::new(d, std::ptr::null()));
Self::set_slot(slot);
}
#[inline(always)]
fn clear_current() {
Self::set_slot(None);
}
fn install_external(aux: Option<ExternalDispatch<Self>>) -> Option<ExternalDispatch<Self>>;
fn current_external() -> Option<ExternalDispatch<Self>>;
fn drive_with<R: CompletionRouter<Self>>(
driver: &mut Self::Driver,
router: &mut R,
) -> io::Result<bool>;
fn dispatch_completions<R: CompletionRouter<Self>>(driver: &mut Self::Driver, router: &mut R);
}
pub trait CompletionRouter<B: CompletionBackend> {
fn on_complete(&mut self, driver: &mut B::Driver, ev: Completion<B>);
}
pub trait ProvidedRingOps {
fn defer(&mut self, bid: u16);
fn ptr_len(&self, bid: u16) -> (*mut u8, usize);
}
pub trait DriverOps: 'static {
type Token: BackendToken;
type ProvidedRing: ProvidedRingOps + 'static;
type IoRequest<O: Unpin + 'static>: Future<Output = (io::Result<u32>, u32, O)> + Unpin + 'static;
fn buf_group(&self) -> u16;
fn provided_ring(&mut self) -> &mut Self::ProvidedRing;
fn arm_accept_multi(&mut self, token: Self::Token, fd: Fd) -> bool;
fn arm_recv_multi(&mut self, token: Self::Token, fd: FixedFd, buf_group: u16) -> bool;
unsafe fn arm_recv_msg_multi(
&mut self,
token: Self::Token,
fd: FixedFd,
buf_group: u16,
msghdr: *const libc::msghdr,
) -> bool;
fn submit_send_tagged(
&mut self,
token: Self::Token,
fd: FixedFd,
ptr: *const u8,
len: u32,
) -> bool;
unsafe fn submit_send_msg_tagged(
&mut self,
token: Self::Token,
fd: FixedFd,
msg: *const libc::msghdr,
) -> bool;
fn cancel_recv(&mut self, token: Self::Token);
fn try_submit_connect_raw(
&mut self,
fd: Fd,
addr: SockAddr,
) -> Result<Self::IoRequest<SockAddr>, (io::Error, SockAddr)>;
fn try_submit_sendmsg_raw<P: SendMsgPacket + Unpin + 'static>(
&mut self,
fd: Fd,
packet: P,
) -> Result<Self::IoRequest<P>, (io::Error, P)>;
fn try_submit_send_raw<B: AsRef<[u8]> + Unpin + 'static>(
&mut self,
fd: Fd,
buf: B,
) -> Result<Self::IoRequest<B>, (io::Error, B)>;
}
pub trait PoolDriver:
CompletionBackend<Driver: DriverOps<Token = <Self as CompletionBackend>::Token>> + 'static
{
}
impl<B> PoolDriver for B
where
B: CompletionBackend + 'static,
B::Driver: DriverOps<Token = B::Token>,
{
}
pub type IoRequest<B, O> = <<B as Backend>::Driver as DriverOps>::IoRequest<O>;
pub type ProvidedRing<B> = <<B as Backend>::Driver as DriverOps>::ProvidedRing;