use super::super::c;
use super::super::conv::{ret, ret_owned_fd, ret_u32};
use crate::fd::{AsFd, AsRawFd, BorrowedFd, RawFd};
#[cfg(not(feature = "rustc-dep-of-std"))]
use crate::fd::{FromFd, FromRawFd, IntoFd, IntoRawFd};
use crate::io::{self, OwnedFd};
use alloc::vec::Vec;
use bitflags::bitflags;
use core::convert::TryInto;
use core::fmt;
use core::marker::PhantomData;
use core::ops::Deref;
use core::ptr::{null, null_mut};
bitflags! {
pub struct CreateFlags: c::c_int {
const CLOEXEC = c::EPOLL_CLOEXEC;
}
}
bitflags! {
#[derive(Default)]
pub struct EventFlags: u32 {
const IN = c::EPOLLIN as u32;
const OUT = c::EPOLLOUT as u32;
const PRI = c::EPOLLPRI as u32;
const ERR = c::EPOLLERR as u32;
const HUP = c::EPOLLHUP as u32;
const ET = c::EPOLLET as u32;
const ONESHOT = c::EPOLLONESHOT as u32;
const WAKEUP = c::EPOLLWAKEUP as u32;
#[cfg(not(target_os = "android"))]
const EXCLUSIVE = c::EPOLLEXCLUSIVE as u32;
}
}
pub struct Ref<'a, T> {
t: T,
_phantom: PhantomData<&'a T>,
}
impl<'a, T> Ref<'a, T> {
#[inline]
fn new(t: T) -> Self {
Self {
t,
_phantom: PhantomData,
}
}
#[inline]
fn consume(self) -> T {
self.t
}
}
impl<'a, T> Deref for Ref<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.t
}
}
impl<'a, T: fmt::Debug> fmt::Debug for Ref<'a, T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
self.t.fmt(fmt)
}
}
pub trait Context {
type Data;
type Target: AsFd;
fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target>;
fn encode(&self, target: Ref<'_, Self::Target>) -> u64;
unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target>;
fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data;
}
pub struct Borrowing<'a> {
_phantom: PhantomData<BorrowedFd<'a>>,
}
impl<'a> Context for Borrowing<'a> {
type Data = BorrowedFd<'a>;
type Target = BorrowedFd<'a>;
#[inline]
fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target> {
Ref::new(data)
}
#[inline]
fn encode(&self, target: Ref<'_, Self::Target>) -> u64 {
target.as_raw_fd() as u64
}
#[inline]
unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target> {
Ref::new(BorrowedFd::<'a>::borrow_raw_fd(raw as RawFd))
}
#[inline]
fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data {
target.consume()
}
}
#[cfg(not(feature = "rustc-dep-of-std"))]
pub struct Owning<'context, T: IntoFd + FromFd> {
_phantom: PhantomData<&'context T>,
}
#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: IntoFd + FromFd> Owning<'context, T> {
#[allow(clippy::new_without_default)] #[inline]
pub fn new() -> Self {
Self {
_phantom: PhantomData,
}
}
}
#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: AsFd + IntoFd + FromFd> Context for Owning<'context, T> {
type Data = T;
type Target = BorrowedFd<'context>;
#[inline]
fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target> {
let raw_fd = data.into_fd().into_raw_fd();
unsafe { Ref::new(BorrowedFd::<'context>::borrow_raw_fd(raw_fd)) }
}
#[inline]
fn encode(&self, target: Ref<'_, Self::Target>) -> u64 {
target.as_fd().as_raw_fd() as u64
}
#[inline]
unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target> {
Ref::new(BorrowedFd::<'context>::borrow_raw_fd(raw as RawFd))
}
#[inline]
fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data {
let raw_fd = target.consume().as_raw_fd();
unsafe { T::from_fd(io_lifetimes::OwnedFd::from_raw_fd(raw_fd)) }
}
}
pub struct Epoll<Context: self::Context> {
epoll_fd: OwnedFd,
context: Context,
}
impl<Context: self::Context> Epoll<Context> {
#[inline]
#[doc(alias = "epoll_create1")]
pub fn new(flags: CreateFlags, context: Context) -> io::Result<Self> {
unsafe {
Ok(Self {
epoll_fd: ret_owned_fd(c::epoll_create1(flags.bits()))?,
context,
})
}
}
#[doc(alias = "epoll_ctl")]
pub fn add(
&self,
data: Context::Data,
event_flags: EventFlags,
) -> io::Result<Ref<'_, Context::Target>> {
unsafe {
let target = self.context.acquire(data);
let raw_fd = target.as_fd().as_raw_fd();
let encoded = self.context.encode(target);
ret(c::epoll_ctl(
self.epoll_fd.as_fd().as_raw_fd(),
c::EPOLL_CTL_ADD,
raw_fd,
&mut c::epoll_event {
events: event_flags.bits(),
r#u64: encoded,
},
))?;
Ok(self.context.decode(encoded))
}
}
#[doc(alias = "epoll_ctl")]
pub fn mod_(
&self,
target: Ref<'_, Context::Target>,
event_flags: EventFlags,
) -> io::Result<()> {
let raw_fd = target.as_fd().as_raw_fd();
let encoded = self.context.encode(target);
unsafe {
ret(c::epoll_ctl(
self.epoll_fd.as_fd().as_raw_fd(),
c::EPOLL_CTL_MOD,
raw_fd,
&mut c::epoll_event {
events: event_flags.bits(),
r#u64: encoded,
},
))
}
}
#[doc(alias = "epoll_ctl")]
pub fn del(&self, target: Ref<'_, Context::Target>) -> io::Result<Context::Data> {
unsafe {
let raw_fd = target.as_fd().as_raw_fd();
ret(c::epoll_ctl(
self.epoll_fd.as_fd().as_raw_fd(),
c::EPOLL_CTL_DEL,
raw_fd,
null_mut(),
))?;
}
Ok(self.context.release(target))
}
#[doc(alias = "epoll_wait")]
pub fn wait<'context>(
&'context self,
event_list: &mut EventVec<'context, Context>,
timeout: c::c_int,
) -> io::Result<()> {
unsafe {
event_list.events.set_len(0);
let nfds = ret_u32(c::epoll_wait(
self.epoll_fd.as_fd().as_raw_fd(),
event_list.events.as_mut_ptr().cast::<c::epoll_event>(),
event_list.events.capacity().try_into().unwrap_or(i32::MAX),
timeout,
))?;
event_list.events.set_len(nfds as usize);
event_list.context = &self.context;
}
Ok(())
}
}
#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: AsFd + IntoFd + FromFd> AsRawFd for Epoll<Owning<'context, T>> {
fn as_raw_fd(&self) -> RawFd {
self.epoll_fd.as_raw_fd()
}
}
#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: AsFd + IntoFd + FromFd> IntoRawFd for Epoll<Owning<'context, T>> {
fn into_raw_fd(self) -> RawFd {
self.epoll_fd.into_raw_fd()
}
}
#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: AsFd + IntoFd + FromFd> FromRawFd for Epoll<Owning<'context, T>> {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self {
epoll_fd: OwnedFd::from_raw_fd(fd),
context: Owning::new(),
}
}
}
#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: AsFd + IntoFd + FromFd> AsFd for Epoll<Owning<'context, T>> {
fn as_fd(&self) -> BorrowedFd<'_> {
self.epoll_fd.as_fd()
}
}
#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: AsFd + IntoFd + FromFd> From<Epoll<Owning<'context, T>>> for OwnedFd {
fn from(epoll: Epoll<Owning<'context, T>>) -> OwnedFd {
epoll.epoll_fd
}
}
#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: AsFd + IntoFd + FromFd> From<OwnedFd> for Epoll<Owning<'context, T>> {
fn from(fd: OwnedFd) -> Self {
Self {
epoll_fd: fd,
context: Owning::new(),
}
}
}
pub struct Iter<'context, Context: self::Context> {
iter: core::slice::Iter<'context, Event>,
context: *const Context,
_phantom: PhantomData<&'context Context>,
}
impl<'context, Context: self::Context> Iterator for Iter<'context, Context> {
type Item = (EventFlags, Ref<'context, Context::Target>);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|event| {
(event.event_flags, unsafe {
(*self.context).decode(event.encoded)
})
})
}
}
#[repr(C)]
#[cfg_attr(
any(
all(
target_arch = "x86",
not(target_env = "musl"),
not(target_os = "android")
),
target_arch = "x86_64"
),
repr(packed)
)]
struct Event {
event_flags: EventFlags,
encoded: u64,
}
pub struct EventVec<'context, Context: self::Context> {
events: Vec<Event>,
context: *const Context,
_phantom: PhantomData<&'context Context>,
}
impl<'context, Context: self::Context> EventVec<'context, Context> {
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
events: Vec::with_capacity(capacity),
context: null(),
_phantom: PhantomData,
}
}
#[inline]
pub fn capacity(&self) -> usize {
self.events.capacity()
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.events.reserve(additional);
}
#[inline]
pub fn reserve_exact(&mut self, additional: usize) {
self.events.reserve_exact(additional);
}
#[inline]
pub fn clear(&mut self) {
self.events.clear();
}
#[inline]
pub fn shrink_to_fit(&mut self) {
self.events.shrink_to_fit();
}
#[inline]
pub fn iter(&self) -> Iter<'_, Context> {
Iter {
iter: self.events.iter(),
context: self.context,
_phantom: PhantomData,
}
}
#[inline]
pub fn len(&mut self) -> usize {
self.events.len()
}
#[inline]
pub fn is_empty(&mut self) -> bool {
self.events.is_empty()
}
}
impl<'context, Context: self::Context> IntoIterator for &'context EventVec<'context, Context> {
type IntoIter = Iter<'context, Context>;
type Item = (EventFlags, Ref<'context, Context::Target>);
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}