From 29b5eef4b7274f93c85e8885d94257817f40412d Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Fri, 30 May 2025 22:46:05 +0800 Subject: [PATCH] make async feature mutual exclusivity In previous version, user can enable async_tokio and async_std features, however when both of them are enabled, tokio will be ignored. After add async_compio feature, when two or three async features are enabled, user may confuse which one will be used. IMO the better way is make these async features are mutual exclusivity, user should only enable one, if more than async feautres are enabled, will compile fail with compile_error! macro. Also if none of the async feature is enabled in aya-log, will compile fail too --- aya-log/Cargo.toml | 1 - aya-log/src/lib.rs | 25 ++++++++++---- aya/src/lib.rs | 3 +- aya/src/maps/perf/async_perf_event_array.rs | 36 ++++++++++----------- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/aya-log/Cargo.toml b/aya-log/Cargo.toml index 8dbdefa5..42e8c1b8 100644 --- a/aya-log/Cargo.toml +++ b/aya-log/Cargo.toml @@ -17,7 +17,6 @@ rust-version.workspace = true workspace = true [features] -default = ["async_tokio"] async_tokio = ["aya/async_tokio", "dep:tokio"] async_std = ["aya/async_std", "dep:async-global-executor"] async_compio = ["aya/async_compio", "dep:compio"] diff --git a/aya-log/src/lib.rs b/aya-log/src/lib.rs index 827ea1d2..bc0ec593 100644 --- a/aya-log/src/lib.rs +++ b/aya-log/src/lib.rs @@ -59,6 +59,23 @@ use std::{ const MAP_NAME: &str = "AYA_LOGS"; +// check async feature mutual exclusivity +#[cfg(all(feature = "async_tokio", feature = "async_std"))] +compile_error!("Cannot enable both async_tokio and async_std features at the same time"); + +#[cfg(all(feature = "async_tokio", feature = "async_compio"))] +compile_error!("Cannot enable both async_tokio and async_compio features at the same time"); + +#[cfg(all(feature = "async_std", feature = "async_compio"))] +compile_error!("Cannot enable both async_std and async_compio features at the same time"); + +#[cfg(not(any( + feature = "async_tokio", + feature = "async_std", + feature = "async_compio" +)))] +compile_error!("Must enable at least one async feature: async_tokio, async_std, or async_compio"); + use aya::{ Ebpf, Pod, maps::{ @@ -183,16 +200,12 @@ impl EbpfLogger { tokio::spawn(fut); } - #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] + #[cfg(feature = "async_std")] { async_global_executor::spawn(fut).detach(); } - #[cfg(all( - not(feature = "async_tokio"), - not(feature = "async_std"), - feature = "async_compio" - ))] + #[cfg(feature = "async_compio")] { compio::runtime::spawn(fut).detach(); } diff --git a/aya/src/lib.rs b/aya/src/lib.rs index f881f7b8..1c8b4ad3 100644 --- a/aya/src/lib.rs +++ b/aya/src/lib.rs @@ -24,13 +24,14 @@ //! * Support for function call relocation and global data maps, which //! allows eBPF programs to make **function calls** and use **global variables //! and initializers**. -//! * **Async support** with both [tokio] and [async-std]. +//! * **Async support** with [tokio], [async-std] and [compio]. //! * Easy to deploy and fast to build: aya doesn't require a kernel build or //! compiled headers, and not even a C toolchain; a release build completes in a matter //! of seconds. //! //! [tokio]: https://docs.rs/tokio //! [async-std]: https://docs.rs/async-std +//! [compio]: https://docs.rs/compio #![doc( html_logo_url = "https://aya-rs.dev/assets/images/crabby.svg", diff --git a/aya/src/maps/perf/async_perf_event_array.rs b/aya/src/maps/perf/async_perf_event_array.rs index deb2e3c1..d225cf03 100644 --- a/aya/src/maps/perf/async_perf_event_array.rs +++ b/aya/src/maps/perf/async_perf_event_array.rs @@ -1,8 +1,14 @@ -#[cfg(all( - not(feature = "async_tokio"), - not(feature = "async_std"), - feature = "async_compio" -))] +// check async feature mutual exclusivity +#[cfg(all(feature = "async_tokio", feature = "async_std"))] +compile_error!("Cannot enable both async_tokio and async_std features at the same time"); + +#[cfg(all(feature = "async_tokio", feature = "async_compio"))] +compile_error!("Cannot enable both async_tokio and async_compio features at the same time"); + +#[cfg(all(feature = "async_std", feature = "async_compio"))] +compile_error!("Cannot enable both async_std and async_compio features at the same time"); + +#[cfg(feature = "async_compio")] use std::os::fd::AsRawFd as _; use std::{ borrow::{Borrow, BorrowMut}, @@ -13,14 +19,10 @@ use std::{ // // We should eventually split async functionality out into separate crates "aya-async-tokio" and // "async-async-std". Presently we arbitrarily choose tokio over async-std when both are requested. -#[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] +#[cfg(feature = "async_std")] use async_io::Async; use bytes::BytesMut; -#[cfg(all( - not(feature = "async_tokio"), - not(feature = "async_std"), - feature = "async_compio" -))] +#[cfg(feature = "async_compio")] use compio::{ driver::{ SharedFd, @@ -121,7 +123,7 @@ impl> AsyncPerfEventArray { let buf = perf_map.open(index, page_count)?; #[cfg(feature = "async_tokio")] let buf = AsyncFd::new(buf)?; - #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] + #[cfg(feature = "async_std")] let buf = Async::new(buf)?; Ok(AsyncPerfEventArrayBuffer { buf }) } @@ -157,7 +159,7 @@ pub struct AsyncPerfEventArrayBuffer> { #[cfg(feature = "async_tokio")] buf: AsyncFd>, - #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] + #[cfg(feature = "async_std")] buf: Async>, } @@ -182,7 +184,7 @@ impl> AsyncPerfEventArrayBuffer { #[cfg(feature = "async_tokio")] let buf = guard.get_inner_mut(); - #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] + #[cfg(feature = "async_std")] let buf = { if !buf.get_ref().readable() { buf.readable().await?; @@ -190,11 +192,7 @@ impl> AsyncPerfEventArrayBuffer { unsafe { buf.get_mut() } }; - #[cfg(all( - not(feature = "async_tokio"), - not(feature = "async_std"), - feature = "async_compio" - ))] + #[cfg(feature = "async_compio")] { let poll_once = PollOnce::new(SharedFd::new(buf.as_raw_fd()), Interest::Readable); runtime::submit(poll_once).await.0?;