use std::io;
use crate::backend::socket::FdSlot;
use crate::backend::token;
use crate::backend::token::{Token, kind};
pub(super) const BUFFER: u32 = 1 << 0;
pub(super) const MORE: u32 = 1 << 1;
pub(super) const BUFFER_SHIFT: u32 = 16;
#[derive(Clone, Copy)]
pub struct Cqe {
pub user_data: u64,
pub result: i32,
pub flags: u32,
}
impl Cqe {
pub const ZERO: Self = Self {
user_data: 0,
result: 0,
flags: 0,
};
pub fn route(self) -> u8 {
(self.user_data >> token::ROUTE_SHIFT) as u8
}
pub fn kind(self) -> u8 {
(self.user_data >> token::KIND_SHIFT) as u8
}
fn more(self) -> bool {
self.flags & MORE != 0
}
fn bid_raw(self) -> u16 {
(self.flags >> BUFFER_SHIFT) as u16
}
fn has_buffer(self) -> bool {
self.flags & BUFFER != 0
}
}
#[derive(Clone, Copy)]
pub enum RecvEvent {
Data { len: u32, bid: u16 },
Discarded { len: u32 },
Eof,
Cancelled,
Starved,
Failed(i32),
}
impl RecvEvent {
fn from_errno(result: i32) -> Self {
match -result {
libc::ECANCELED => Self::Cancelled,
libc::ENOBUFS => {
crate::memstats::enobufs_inc();
Self::Starved
}
libc::EAGAIN | libc::EINTR => Self::Starved,
errno => Self::Failed(errno),
}
}
}
#[derive(Clone, Copy)]
pub enum SendEvent {
Sent(u32),
Failed(i32),
}
#[derive(Clone, Copy)]
pub enum WriteEvent {
Wrote(u32),
Failed(i32),
}
#[derive(Clone, Copy)]
pub enum SyncEvent {
Synced,
Failed(i32),
}
#[derive(Clone, Copy)]
pub enum OpenEvent {
Opened(i32),
Failed(i32),
}
#[derive(Clone, Copy)]
pub enum ReadEvent {
Read(u32),
Eof,
Failed(i32),
}
#[derive(Clone, Copy)]
pub enum SpliceEvent {
Moved(u32),
Eof,
Failed(i32),
}
#[derive(Clone, Copy)]
pub enum AcceptEvent {
Accepted(FdSlot),
Failed,
}
pub enum SocketEvent {
Created,
Failed(io::Error),
}
pub enum ConnectEvent {
Connected,
Failed(io::Error),
}
pub enum Event {
Accept(Token, bool, AcceptEvent),
Recv(Token, bool, RecvEvent),
Send(Token, SendEvent),
Timer(Token),
Socket(Token, SocketEvent),
Connect(Token, ConnectEvent),
Write(Token, WriteEvent),
Sync(Token, SyncEvent),
Open(Token, OpenEvent),
Read(Token, ReadEvent),
Splice(Token, SpliceEvent),
}
impl TryFrom<Cqe> for Event {
type Error = ();
fn try_from(c: Cqe) -> Result<Self, ()> {
match c.kind() {
kind::ACCEPT => {
let e = match c.result {
n if n >= 0 => AcceptEvent::Accepted(FdSlot::new(n as u32)),
_ => AcceptEvent::Failed,
};
Ok(Self::Accept(Token::from_raw(c.user_data), c.more(), e))
}
kind::RECV => {
let e = match c.result {
n if n > 0 => {
if !c.has_buffer() {
debug_assert!(false, "RECV data cqe without buffer flag");
return Err(());
}
RecvEvent::Data {
len: n as u32,
bid: c.bid_raw(),
}
}
0 => RecvEvent::Eof,
n => RecvEvent::from_errno(n),
};
Ok(Self::Recv(Token::from_raw(c.user_data), c.more(), e))
}
kind::RECV_DISCARD => {
let e = match c.result {
n if n > 0 => RecvEvent::Discarded { len: n as u32 },
0 => RecvEvent::Eof,
n => RecvEvent::from_errno(n),
};
Ok(Self::Recv(Token::from_raw(c.user_data), c.more(), e))
}
kind::SEND => {
let e = if c.result >= 0 {
SendEvent::Sent(c.result as u32)
} else {
SendEvent::Failed(-c.result)
};
Ok(Self::Send(Token::from_raw(c.user_data), e))
}
kind::WRITE => {
let e = if c.result >= 0 {
WriteEvent::Wrote(c.result as u32)
} else {
WriteEvent::Failed(-c.result)
};
Ok(Self::Write(Token::from_raw(c.user_data), e))
}
kind::SYNC => {
let e = if c.result >= 0 {
SyncEvent::Synced
} else {
SyncEvent::Failed(-c.result)
};
Ok(Self::Sync(Token::from_raw(c.user_data), e))
}
kind::OPEN => {
let e = if c.result >= 0 {
OpenEvent::Opened(c.result)
} else {
OpenEvent::Failed(-c.result)
};
Ok(Self::Open(Token::from_raw(c.user_data), e))
}
kind::READ => {
let e = match c.result {
n if n > 0 => ReadEvent::Read(n as u32),
0 => ReadEvent::Eof,
n => ReadEvent::Failed(-n),
};
Ok(Self::Read(Token::from_raw(c.user_data), e))
}
kind::SPLICE => {
let e = match c.result {
n if n > 0 => SpliceEvent::Moved(n as u32),
0 => SpliceEvent::Eof,
n => SpliceEvent::Failed(-n),
};
Ok(Self::Splice(Token::from_raw(c.user_data), e))
}
kind::TIMER => Ok(Self::Timer(Token::from_raw(c.user_data))),
kind::SOCKET => {
let e = if c.result >= 0 {
SocketEvent::Created
} else {
SocketEvent::Failed(io::Error::from_raw_os_error(-c.result))
};
Ok(Self::Socket(Token::from_raw(c.user_data), e))
}
kind::CONNECT => {
let e = if c.result >= 0 {
ConnectEvent::Connected
} else {
ConnectEvent::Failed(io::Error::from_raw_os_error(-c.result))
};
Ok(Self::Connect(Token::from_raw(c.user_data), e))
}
_ => Err(()),
}
}
}
impl Event {
pub fn route(&self) -> u8 {
match self {
Self::Accept(t, ..) => t.route(),
Self::Recv(t, ..) => t.route(),
Self::Send(t, _) => t.route(),
Self::Timer(t) => t.route(),
Self::Socket(t, _) => t.route(),
Self::Connect(t, _) => t.route(),
Self::Write(t, _) => t.route(),
Self::Sync(t, _) => t.route(),
Self::Open(t, _) => t.route(),
Self::Read(t, _) => t.route(),
Self::Splice(t, _) => t.route(),
}
}
}