Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
target
Cargo.lock
/.vscode
Comment thread
notgull marked this conversation as resolved.
Outdated
142 changes: 54 additions & 88 deletions src/backend/libc/io/epoll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
//! accept, bind_v4, listen, socket, AddressFamily, Ipv4Addr, Protocol, SocketAddrV4,
//! SocketType,
//! };
//! use std::collections::HashMap;
//! use std::os::unix::io::AsRawFd;
//!
//! // Create a socket and listen on it.
Expand All @@ -26,29 +27,35 @@
//!
//! // Create an epoll object. Using `Owning` here means the epoll object will
//! // take ownership of the file descriptors registered with it.
//! let epoll = Epoll::new(epoll::CreateFlags::CLOEXEC, epoll::Owning::new())?;
//!
//! // Remember the socket raw fd, which we use for comparisons only.
//! let raw_listen_sock = listen_sock.as_fd().as_raw_fd();
//! let epoll = Epoll::new(epoll::CreateFlags::CLOEXEC)?;
//!
//! // Register the socket with the epoll object.
//! epoll.add(listen_sock, epoll::EventFlags::IN)?;
//! epoll.add(&listen_sock, 1, epoll::EventFlags::IN)?;
//!
//! // Keep track of the sockets we've opened.
//! let mut next_id = 2;
//! let mut sockets = HashMap::new();
//!
//! // Process events.
//! let mut event_list = epoll::EventVec::with_capacity(4);
//! loop {
//! epoll.wait(&mut event_list, -1)?;
//! for (_event_flags, target) in &event_list {
//! if target.as_raw_fd() == raw_listen_sock {
//! if target == 1 {
//! // Accept a new connection, set it to non-blocking, and
//! // register to be notified when it's ready to write to.
//! let conn_sock = accept(&*target)?;
//! let conn_sock = accept(&listen_sock)?;
//! ioctl_fionbio(&conn_sock, true)?;
//! epoll.add(conn_sock, epoll::EventFlags::OUT | epoll::EventFlags::ET)?;
//! epoll.add(&conn_sock, next_id, epoll::EventFlags::OUT | epoll::EventFlags::ET)?;
//!
//! // Keep track of the socket.
//! sockets.insert(next_id, conn_sock);
//! next_id += 1;
//! } else {
//! // Write a message to the stream and then unregister it.
//! write(&*target, b"hello\n")?;
//! let _ = epoll.del(target)?;
//! let target = sockets.remove(&target).unwrap();
//! write(&target, b"hello\n")?;
//! let _ = epoll.del(&target)?;
//! }
//! }
//! }
Expand All @@ -66,11 +73,7 @@ use crate::io;
use alloc::vec::Vec;
use bitflags::bitflags;
use core::convert::TryInto;
use core::marker::PhantomData;
use core::ptr::{null, null_mut};

#[doc(inline)]
pub use crate::io::context::*;
use core::ptr::null_mut;

bitflags! {
/// `EPOLL_*` for use with [`Epoll::new`].
Expand Down Expand Up @@ -116,25 +119,23 @@ bitflags! {

/// An "epoll", an interface to an OS object allowing one to repeatedly wait
/// for events from a set of file descriptors efficiently.
pub struct Epoll<Context: self::Context> {
pub struct Epoll {
epoll_fd: OwnedFd,
context: Context,
}

impl<Context: self::Context> Epoll<Context> {
impl Epoll {
/// `epoll_create1(flags)`—Creates a new `Epoll`.
///
/// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file
/// descriptor from being implicitly passed across `exec` boundaries.
#[inline]
#[doc(alias = "epoll_create1")]
pub fn new(flags: CreateFlags, context: Context) -> io::Result<Self> {
pub fn new(flags: CreateFlags) -> io::Result<Self> {
// Safety: We're calling `epoll_create1` via FFI and we know how it
// behaves.
unsafe {
Ok(Self {
epoll_fd: ret_owned_fd(c::epoll_create1(flags.bits()))?,
context,
})
}
}
Expand All @@ -145,27 +146,20 @@ impl<Context: self::Context> Epoll<Context> {
/// This registers interest in any of the events set in `events` occurring
/// on the file descriptor associated with `data`.
#[doc(alias = "epoll_ctl")]
pub fn add(
&self,
data: Context::Data,
event_flags: EventFlags,
) -> io::Result<Ref<'_, Context::Target>> {
pub fn add(&self, source: &impl AsFd, data: u64, event_flags: EventFlags) -> io::Result<()> {
// Safety: We're calling `epoll_ctl` via FFI and we know how it
// behaves.
unsafe {
let target = self.context.acquire(data);
let raw_fd = target.as_fd().as_raw_fd();
let encoded = self.context.encode(target);
let raw_fd = source.as_fd().as_raw_fd();
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,
r#u64: data,
},
))?;
Ok(self.context.decode(encoded))
))
}
}

Expand All @@ -174,13 +168,9 @@ impl<Context: self::Context> Epoll<Context> {
///
/// This sets the events of interest with `target` to `events`.
#[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);
pub fn mod_(&self, source: &impl AsFd, data: u64, event_flags: EventFlags) -> io::Result<()> {
let raw_fd = source.as_fd().as_raw_fd();

// Safety: We're calling `epoll_ctl` via FFI and we know how it
// behaves.
unsafe {
Expand All @@ -190,7 +180,7 @@ impl<Context: self::Context> Epoll<Context> {
raw_fd,
&mut c::epoll_event {
events: event_flags.bits(),
r#u64: encoded,
r#u64: data,
},
))
}
Expand All @@ -201,19 +191,18 @@ impl<Context: self::Context> Epoll<Context> {
///
/// This also returns the owning `Data`.
#[doc(alias = "epoll_ctl")]
pub fn del(&self, target: Ref<'_, Context::Target>) -> io::Result<Context::Data> {
pub fn del(&self, source: &impl AsFd) -> io::Result<()> {
// Safety: We're calling `epoll_ctl` via FFI and we know how it
// behaves.
unsafe {
let raw_fd = target.as_fd().as_raw_fd();
let raw_fd = source.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))
}

/// `epoll_wait(self, events, timeout)`—Waits for registered events of
Expand All @@ -222,11 +211,7 @@ impl<Context: self::Context> Epoll<Context> {
/// For each event of interest, an element is written to `events`. On
/// success, this returns the number of written elements.
#[doc(alias = "epoll_wait")]
pub fn wait<'context>(
&'context self,
event_list: &mut EventVec<'context, Context>,
timeout: c::c_int,
) -> io::Result<()> {
pub fn wait(&self, event_list: &mut EventVec, timeout: c::c_int) -> io::Result<()> {
// Safety: We're calling `epoll_wait` via FFI and we know how it
// behaves.
unsafe {
Expand All @@ -238,84 +223,71 @@ impl<Context: self::Context> Epoll<Context> {
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 + Into<OwnedFd> + From<OwnedFd>> AsRawFd for Epoll<Owning<'context, T>> {
impl AsRawFd for Epoll {
fn as_raw_fd(&self) -> RawFd {
self.epoll_fd.as_raw_fd()
}
}

#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> IntoRawFd for Epoll<Owning<'context, T>> {
impl IntoRawFd for Epoll {
fn into_raw_fd(self) -> RawFd {
self.epoll_fd.into_raw_fd()
}
}

#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> FromRawFd for Epoll<Owning<'context, T>> {
impl FromRawFd for Epoll {
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 + Into<OwnedFd> + From<OwnedFd>> AsFd for Epoll<Owning<'context, T>> {
impl AsFd for Epoll {
fn as_fd(&self) -> BorrowedFd<'_> {
self.epoll_fd.as_fd()
}
}

#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> From<Epoll<Owning<'context, T>>>
for OwnedFd
{
fn from(epoll: Epoll<Owning<'context, T>>) -> Self {
impl From<Epoll> for OwnedFd {
fn from(epoll: Epoll) -> Self {
epoll.epoll_fd
}
}

#[cfg(not(feature = "rustc-dep-of-std"))]
impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> From<OwnedFd>
for Epoll<Owning<'context, T>>
{
impl From<OwnedFd> for Epoll {
fn from(fd: OwnedFd) -> Self {
Self {
epoll_fd: fd,
context: Owning::new(),
}
Self { epoll_fd: fd }
}
}

/// An iterator over the `Event`s in an `EventVec`.
pub struct Iter<'context, Context: self::Context> {
iter: core::slice::Iter<'context, Event>,
context: *const Context,
_phantom: PhantomData<&'context Context>,
pub struct Iter<'a> {
iter: core::slice::Iter<'a, Event>,
}

impl<'context, Context: self::Context> Iterator for Iter<'context, Context> {
type Item = (EventFlags, Ref<'context, Context::Target>);
impl<'a> Iterator for Iter<'a> {
type Item = (EventFlags, u64);

fn next(&mut self) -> Option<Self::Item> {
// Safety: `self.context` is guaranteed to be valid because we hold
// `'context` for it. And we know this event is associated with this
// context because `wait` sets both.
self.iter.next().map(|event| {
(event.event_flags, unsafe {
(*self.context).decode(event.encoded)
})
})
self.iter
.next()
.map(|event| (event.event_flags, event.encoded))
}
}

Expand All @@ -341,20 +313,16 @@ struct Event {
}

/// A vector of `Event`s, plus context for interpreting them.
pub struct EventVec<'context, Context: self::Context> {
pub struct EventVec {
events: Vec<Event>,
context: *const Context,
_phantom: PhantomData<&'context Context>,
}

impl<'context, Context: self::Context> EventVec<'context, Context> {
impl EventVec {
/// Constructs an `EventVec` with memory for `capacity` `Event`s.
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
events: Vec::with_capacity(capacity),
context: null(),
_phantom: PhantomData,
}
}

Expand Down Expand Up @@ -390,11 +358,9 @@ impl<'context, Context: self::Context> EventVec<'context, Context> {

/// Returns an iterator over the `Event`s in this `EventVec`.
#[inline]
pub fn iter(&self) -> Iter<'_, Context> {
pub fn iter(&self) -> Iter<'_> {
Iter {
iter: self.events.iter(),
context: self.context,
_phantom: PhantomData,
}
}

Expand All @@ -411,9 +377,9 @@ impl<'context, Context: self::Context> EventVec<'context, Context> {
}
}

impl<'context, Context: self::Context> IntoIterator for &'context EventVec<'context, Context> {
type IntoIter = Iter<'context, Context>;
type Item = (EventFlags, Ref<'context, Context::Target>);
impl<'a> IntoIterator for &'a EventVec {
type IntoIter = Iter<'a>;
type Item = (EventFlags, u64);

#[inline]
fn into_iter(self) -> Self::IntoIter {
Expand Down
Loading