#![allow(unsafe_code)]
use crate::backend::c;
use crate::backend::event::syscalls;
use crate::fd::{AsFd, AsRawFd, OwnedFd};
use crate::io;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use bitflags::bitflags;
use core::ffi::c_void;
use core::hash::{Hash, Hasher};
use core::slice;
bitflags! {
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct CreateFlags: c::c_uint {
const CLOEXEC = linux_raw_sys::general::EPOLL_CLOEXEC;
const _ = !0;
}
}
bitflags! {
#[repr(transparent)]
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct EventFlags: u32 {
const IN = linux_raw_sys::general::EPOLLIN as u32;
const OUT = linux_raw_sys::general::EPOLLOUT as u32;
const PRI = linux_raw_sys::general::EPOLLPRI as u32;
const ERR = linux_raw_sys::general::EPOLLERR as u32;
const HUP = linux_raw_sys::general::EPOLLHUP as u32;
const RDNORM = linux_raw_sys::general::EPOLLRDNORM as u32;
const RDBAND = linux_raw_sys::general::EPOLLRDBAND as u32;
const WRNORM = linux_raw_sys::general::EPOLLWRNORM as u32;
const WRBAND = linux_raw_sys::general::EPOLLWRBAND as u32;
const MSG = linux_raw_sys::general::EPOLLMSG as u32;
const RDHUP = linux_raw_sys::general::EPOLLRDHUP as u32;
const ET = linux_raw_sys::general::EPOLLET as u32;
const ONESHOT = linux_raw_sys::general::EPOLLONESHOT as u32;
const WAKEUP = linux_raw_sys::general::EPOLLWAKEUP as u32;
const EXCLUSIVE = linux_raw_sys::general::EPOLLEXCLUSIVE as u32;
const _ = !0;
}
}
#[inline]
#[doc(alias = "epoll_create1")]
pub fn create(flags: CreateFlags) -> io::Result<OwnedFd> {
syscalls::epoll_create(flags)
}
#[doc(alias = "epoll_ctl")]
#[inline]
pub fn add(
epoll: impl AsFd,
source: impl AsFd,
data: EventData,
event_flags: EventFlags,
) -> io::Result<()> {
unsafe {
syscalls::epoll_add(
epoll.as_fd(),
source.as_fd().as_raw_fd(),
&Event {
flags: event_flags,
data,
},
)
}
}
#[doc(alias = "epoll_ctl")]
#[inline]
pub fn modify(
epoll: impl AsFd,
source: impl AsFd,
data: EventData,
event_flags: EventFlags,
) -> io::Result<()> {
unsafe {
let raw_fd = source.as_fd().as_raw_fd();
syscalls::epoll_mod(
epoll.as_fd(),
raw_fd,
&Event {
flags: event_flags,
data,
},
)
}
}
#[doc(alias = "epoll_ctl")]
#[inline]
pub fn delete(epoll: impl AsFd, source: impl AsFd) -> io::Result<()> {
unsafe {
let raw_fd = source.as_fd().as_raw_fd();
syscalls::epoll_del(epoll.as_fd(), raw_fd)
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
#[inline]
pub fn wait(epoll: impl AsFd, event_list: &mut EventVec, timeout: c::c_int) -> io::Result<()> {
unsafe {
event_list.events.set_len(0);
let nfds = syscalls::epoll_wait(
epoll.as_fd(),
event_list.events[..].as_mut_ptr().cast(),
event_list.events.capacity(),
timeout,
)?;
event_list.events.set_len(nfds);
}
Ok(())
}
pub struct Iter<'a> {
iter: core::iter::Copied<slice::Iter<'a, Event>>,
}
impl<'a> Iterator for Iter<'a> {
type Item = Event;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
#[repr(C)]
#[cfg_attr(target_arch = "x86_64", repr(packed))]
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Event {
pub flags: EventFlags,
pub data: EventData,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union EventData {
as_u64: u64,
sixty_four_bit_pointer: SixtyFourBitPointer,
}
impl EventData {
#[inline]
pub const fn new_u64(value: u64) -> Self {
Self { as_u64: value }
}
#[inline]
pub const fn new_ptr(value: *mut c_void) -> Self {
Self {
sixty_four_bit_pointer: SixtyFourBitPointer {
pointer: value,
#[cfg(target_pointer_width = "32")]
_padding: 0,
},
}
}
#[inline]
pub fn u64(self) -> u64 {
unsafe { self.as_u64 }
}
#[inline]
pub fn ptr(self) -> *mut c_void {
unsafe { self.sixty_four_bit_pointer.pointer }
}
}
impl PartialEq for EventData {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.u64() == other.u64()
}
}
impl Eq for EventData {}
impl Hash for EventData {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.u64().hash(state)
}
}
#[repr(C)]
#[derive(Copy, Clone)]
struct SixtyFourBitPointer {
#[cfg(target_endian = "big")]
#[cfg(target_pointer_width = "32")]
_padding: u32,
pointer: *mut c_void,
#[cfg(target_endian = "little")]
#[cfg(target_pointer_width = "32")]
_padding: u32,
}
#[cfg(feature = "alloc")]
pub struct EventVec {
events: Vec<Event>,
}
#[cfg(feature = "alloc")]
impl EventVec {
#[inline]
pub unsafe fn from_raw_parts(ptr: *mut Event, len: usize, capacity: usize) -> Self {
Self {
events: Vec::from_raw_parts(ptr, len, capacity),
}
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
events: Vec::with_capacity(capacity),
}
}
#[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<'_> {
Iter {
iter: self.events.iter().copied(),
}
}
#[inline]
pub fn len(&mut self) -> usize {
self.events.len()
}
#[inline]
pub fn is_empty(&mut self) -> bool {
self.events.is_empty()
}
}
#[cfg(feature = "alloc")]
impl<'a> IntoIterator for &'a EventVec {
type IntoIter = Iter<'a>;
type Item = Event;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[test]
fn test_epoll_layouts() {
check_renamed_type!(Event, epoll_event);
check_renamed_type!(Event, epoll_event);
check_renamed_struct_renamed_field!(Event, epoll_event, flags, events);
check_renamed_struct_renamed_field!(Event, epoll_event, data, data);
}