Skip to content

Commit

Permalink
Merge branch 'master' into fix-detect-connection-fail
Browse files Browse the repository at this point in the history
  • Loading branch information
irvingoujAtDevolution authored Mar 20, 2024
2 parents 20996c2 + 50454d1 commit bf30796
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 33 deletions.
17 changes: 11 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,10 @@ jobs:
RUSTFLAGS: ${{ env.RUSTFLAGS }} --cfg polling_test_epoll_pipe
if: startsWith(matrix.os, 'ubuntu')
- run: cargo hack build --feature-powerset --no-dev-deps
- name: Add rust-src
if: startsWith(matrix.rust, 'nightly')
run: rustup component add rust-src
# TODO: broken due to https://github.com/rust-lang/rust/pull/119026.
# - name: Check selected Tier 3 targets
# if: startsWith(matrix.rust, 'nightly') && matrix.os == 'ubuntu-latest'
# run: cargo check -Z build-std --target=riscv32imc-esp-espidf
- name: Check haiku
if: startsWith(matrix.rust, 'nightly') && matrix.os == 'ubuntu-latest'
run: cargo check -Z build-std --target x86_64-unknown-haiku
- name: Clone async-io
run: git clone https://github.com/smol-rs/async-io.git
# The async-io Cargo.toml already has a patch section at the bottom, so we
Expand All @@ -93,6 +87,9 @@ jobs:
run: rustup update stable
- name: Install cross
uses: taiki-e/install-action@cross
- name: Add rust-src
if: startsWith(matrix.rust, 'nightly')
run: rustup component add rust-src
# We don't test BSDs, since we already test them in Cirrus.
- name: Android
if: startsWith(matrix.os, 'ubuntu')
Expand All @@ -118,9 +115,17 @@ jobs:
rustup target add x86_64-unknown-illumos
cargo build --target x86_64-unknown-illumos
- name: Redox
if: startsWith(matrix.rust, 'nightly') && matrix.os == 'ubuntu-latest'
run: |
rustup target add x86_64-unknown-redox
cargo check --target x86_64-unknown-redox
- name: HermitOS
if: startsWith(matrix.rust, 'nightly') && matrix.os == 'ubuntu-latest'
run: |
cargo -Zbuild-std check --target x86_64-unknown-hermit
- name: Check haiku
if: startsWith(matrix.rust, 'nightly') && matrix.os == 'ubuntu-latest'
run: cargo check -Z build-std --target x86_64-unknown-haiku

wine:
runs-on: ubuntu-22.04
Expand Down
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ rustdoc-args = ["--cfg", "docsrs"]
cfg-if = "1"
tracing = { version = "0.1.37", default-features = false }

[target.'cfg(any(unix, target_os = "fuchsia", target_os = "vxworks"))'.dependencies]
rustix = { version = "0.38.31", features = ["event", "fs", "pipe", "process", "std", "time"], default-features = false }
[target.'cfg(any(unix, target_os = "fuchsia", target_os = "vxworks"))'.dependencies.rustix]
version = "0.38.31"
features = ["event", "fs", "pipe", "process", "std", "time"]
default-features = false

[target.'cfg(windows)'.dependencies]
concurrent-queue = "2.2.0"
Expand All @@ -43,6 +45,9 @@ features = [
"Win32_System_WindowsProgramming",
]

[target.'cfg(target_os = "hermit")'.dependencies.hermit-abi]
version = "0.3.9"

[dev-dependencies]
easy-parallel = "3.1.0"
fastrand = "2.0.0"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ https://docs.rs/polling)
Portable interface to epoll, kqueue, event ports, and IOCP.

Supported platforms:
- [epoll](https://en.wikipedia.org/wiki/Epoll): Linux, Android
- [epoll](https://en.wikipedia.org/wiki/Epoll): Linux, Android, RedoxOS
- [kqueue](https://en.wikipedia.org/wiki/Kqueue): macOS, iOS, tvOS, watchOS, FreeBSD, NetBSD, OpenBSD,
DragonFly BSD
- [event ports](https://illumos.org/man/port_create): illumos, Solaris
- [poll](https://en.wikipedia.org/wiki/Poll_(Unix)): VxWorks, Fuchsia, other Unix systems
- [poll](https://en.wikipedia.org/wiki/Poll_(Unix)): VxWorks, Fuchsia, HermitOS, other Unix systems
- [IOCP](https://learn.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports): Windows, Wine (version 7.13+)

Polling is done in oneshot mode, which means interest in I/O events needs to be reset after
Expand Down
8 changes: 0 additions & 8 deletions src/iocp/port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,11 +296,3 @@ impl<T: CompletionHandle> Drop for OverlappedEntry<T> {
drop(unsafe { self.packet() });
}
}

struct CallOnDrop<F: FnMut()>(F);

impl<F: FnMut()> Drop for CallOnDrop<F> {
fn drop(&mut self) {
(self.0)();
}
}
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! - [kqueue](https://en.wikipedia.org/wiki/Kqueue): macOS, iOS, tvOS, watchOS, FreeBSD, NetBSD, OpenBSD,
//! DragonFly BSD
//! - [event ports](https://illumos.org/man/port_create): illumos, Solaris
//! - [poll](https://en.wikipedia.org/wiki/Poll_(Unix)): VxWorks, Fuchsia, other Unix systems
//! - [poll](https://en.wikipedia.org/wiki/Poll_(Unix)): VxWorks, Fuchsia, HermitOS, other Unix systems
//! - [IOCP](https://learn.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports): Windows, Wine (version 7.13+)
//!
//! By default, polling is done in oneshot mode, which means interest in I/O events needs to
Expand Down Expand Up @@ -107,6 +107,7 @@ cfg_if! {
use kqueue as sys;
} else if #[cfg(any(
target_os = "vxworks",
target_os = "hermit",
target_os = "fuchsia",
target_os = "horizon",
unix,
Expand Down Expand Up @@ -1038,8 +1039,11 @@ impl fmt::Debug for Poller {
}

cfg_if! {
if #[cfg(unix)] {
if #[cfg(any(unix, target_os = "hermit"))] {
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, RawFd, AsFd, BorrowedFd};
#[cfg(target_os = "hermit")]
use std::os::hermit::io::{AsRawFd, RawFd, AsFd, BorrowedFd};

/// A resource with a raw file descriptor.
pub trait AsRawSource {
Expand Down
203 changes: 190 additions & 13 deletions src/poll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Condvar, Mutex};
use std::time::{Duration, Instant};

use rustix::event::{poll, PollFd, PollFlags};
#[cfg(not(target_os = "hermit"))]
use rustix::fd::{AsFd, AsRawFd, BorrowedFd};
#[cfg(target_os = "hermit")]
use std::os::hermit::io::{AsFd, AsRawFd, BorrowedFd};

use syscall::{poll, PollFd, PollFlags};

// std::os::unix doesn't exist on Fuchsia
type RawFd = std::os::raw::c_int;
Expand Down Expand Up @@ -448,7 +452,182 @@ fn cvt_mode_as_remove(mode: PollMode) -> io::Result<bool> {
}
}

#[cfg(not(target_os = "espidf"))]
#[cfg(unix)]
mod syscall {
pub(super) use rustix::event::{poll, PollFd, PollFlags};

#[cfg(target_os = "espidf")]
pub(super) use rustix::event::{eventfd, EventfdFlags};
#[cfg(target_os = "espidf")]
pub(super) use rustix::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd};
#[cfg(target_os = "espidf")]
pub(super) use rustix::io::{read, write};
}

#[cfg(target_os = "hermit")]
mod syscall {
// TODO: Remove this shim once HermitOS is supported in Rustix.

use std::fmt;
use std::io;
use std::marker::PhantomData;
use std::ops::BitOr;

pub(super) use std::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};

/// Create an eventfd.
pub(super) fn eventfd(count: u64, _flags: EventfdFlags) -> io::Result<OwnedFd> {
let fd = unsafe { hermit_abi::eventfd(count, 0) };

if fd < 0 {
Err(io::Error::from_raw_os_error(unsafe {
hermit_abi::get_errno()
}))
} else {
Ok(unsafe { OwnedFd::from_raw_fd(fd) })
}
}

/// Read some bytes.
pub(super) fn read(fd: BorrowedFd<'_>, bytes: &mut [u8]) -> io::Result<usize> {
let count = unsafe { hermit_abi::read(fd.as_raw_fd(), bytes.as_mut_ptr(), bytes.len()) };

cvt(count)
}

/// Write some bytes.
pub(super) fn write(fd: BorrowedFd<'_>, bytes: &[u8]) -> io::Result<usize> {
let count = unsafe { hermit_abi::write(fd.as_raw_fd(), bytes.as_ptr(), bytes.len()) };

cvt(count)
}

/// Safe wrapper around the `poll` system call.
pub(super) fn poll(fds: &mut [PollFd<'_>], timeout: i32) -> io::Result<usize> {
let call = unsafe {
hermit_abi::poll(
fds.as_mut_ptr() as *mut hermit_abi::pollfd,
fds.len(),
timeout,
)
};

cvt(call as isize)
}

/// Safe wrapper around `pollfd`.
#[repr(transparent)]
pub(super) struct PollFd<'a> {
inner: hermit_abi::pollfd,
_lt: PhantomData<BorrowedFd<'a>>,
}

impl<'a> PollFd<'a> {
pub(super) fn from_borrowed_fd(fd: BorrowedFd<'a>, inflags: PollFlags) -> Self {
Self {
inner: hermit_abi::pollfd {
fd: fd.as_raw_fd(),
events: inflags.0,
revents: 0,
},
_lt: PhantomData,
}
}

pub(super) fn revents(&self) -> PollFlags {
PollFlags(self.inner.revents)
}
}

impl AsFd for PollFd<'_> {
fn as_fd(&self) -> BorrowedFd<'_> {
unsafe { BorrowedFd::borrow_raw(self.inner.fd) }
}
}

impl fmt::Debug for PollFd<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PollFd")
.field("fd", &format_args!("0x{:x}", self.inner.fd))
.field("events", &PollFlags(self.inner.events))
.field("revents", &PollFlags(self.inner.revents))
.finish()
}
}

/// Wrapper around polling flags.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(super) struct PollFlags(i16);

impl PollFlags {
/// Empty set of flags.
pub(super) const fn empty() -> Self {
Self(0)
}

pub(super) const IN: PollFlags = PollFlags(hermit_abi::POLLIN);
pub(super) const OUT: PollFlags = PollFlags(hermit_abi::POLLOUT);
pub(super) const WRBAND: PollFlags = PollFlags(hermit_abi::POLLWRBAND);
pub(super) const ERR: PollFlags = PollFlags(hermit_abi::POLLERR);
pub(super) const HUP: PollFlags = PollFlags(hermit_abi::POLLHUP);
pub(super) const PRI: PollFlags = PollFlags(hermit_abi::POLLPRI);

/// Tell if this contains some flags.
pub(super) fn contains(self, flags: PollFlags) -> bool {
self.0 & flags.0 != 0
}

/// Set a flag.
pub(super) fn set(&mut self, flags: PollFlags, set: bool) {
if set {
self.0 |= flags.0;
} else {
self.0 &= !(flags.0);
}
}

/// Tell if this is empty.
pub(super) fn is_empty(self) -> bool {
self.0 == 0
}

/// Tell if this intersects with some flags.
pub(super) fn intersects(self, flags: PollFlags) -> bool {
self.contains(flags)
}
}

impl BitOr for PollFlags {
type Output = PollFlags;

fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}

#[derive(Debug, Copy, Clone)]
pub(super) struct EventfdFlags;

impl EventfdFlags {
pub(super) fn empty() -> Self {
Self
}
}

/// Convert a number to an actual result.
#[inline]
fn cvt(len: isize) -> io::Result<usize> {
if len < 0 {
Err(io::Error::from_raw_os_error(unsafe {
hermit_abi::get_errno()
}))
} else {
Ok(len as usize)
}
}
}

#[cfg(not(any(target_os = "espidf", target_os = "hermit")))]
mod notify {
use std::io;

Expand Down Expand Up @@ -539,16 +718,14 @@ mod notify {
}
}

#[cfg(target_os = "espidf")]
#[cfg(any(target_os = "espidf", target_os = "hermit"))]
mod notify {
use std::io;
use std::mem;

use rustix::event::PollFlags;
use rustix::event::{eventfd, EventfdFlags};

use rustix::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd};
use rustix::io::{read, write};
use super::syscall::{
eventfd, read, write, AsFd, AsRawFd, BorrowedFd, EventfdFlags, OwnedFd, PollFlags, RawFd,
};

/// A notification pipe.
///
Expand Down Expand Up @@ -578,16 +755,16 @@ mod notify {

let flags = EventfdFlags::empty();
let event_fd = eventfd(0, flags).map_err(|err| {
match err {
rustix::io::Errno::PERM => {
match io::Error::from(err) {
err if err.kind() == io::ErrorKind::PermissionDenied => {
// EPERM can happen if the eventfd isn't initialized yet.
// Tell the user to call esp_vfs_eventfd_register.
io::Error::new(
io::ErrorKind::PermissionDenied,
"failed to initialize eventfd for polling, try calling `esp_vfs_eventfd_register`"
)
},
err => io::Error::from(err),
err => err,
}
})?;

Expand All @@ -606,14 +783,14 @@ mod notify {

/// Notifies the `Poller` instance via the eventfd file descriptor.
pub(super) fn notify(&self) -> Result<(), io::Error> {
write(&self.event_fd, &1u64.to_ne_bytes())?;
write(self.event_fd.as_fd(), &1u64.to_ne_bytes())?;

Ok(())
}

/// Pops a notification (if any) from the eventfd file descriptor.
pub(super) fn pop_notification(&self) -> Result<(), io::Error> {
read(&self.event_fd, &mut [0; mem::size_of::<u64>()])?;
read(self.event_fd.as_fd(), &mut [0; mem::size_of::<u64>()])?;

Ok(())
}
Expand Down

0 comments on commit bf30796

Please sign in to comment.