use alloc::{borrow::Cow, sync::Arc};
use core::ops::{Deref, DerefMut};
use ax_errno::{AxError, AxResult};
use ax_kspin::{SpinNoPreempt, SpinNoPreemptGuard};
use axpoll::{PollSet, Pollable};
use kbpf_basic::{
PollWaker,
map::{BpfMapMeta, UnifiedMap, bpf_map_create},
};
use crate::{
ebpf::transform::{EbpfKernelAuxiliary, PerCpuImpl},
file::{FileLike, Kstat},
};
pub struct BpfMap {
unified_map: SpinNoPreempt<UnifiedMap>,
poll_ready: Arc<PollSetWrapper>,
}
impl core::fmt::Debug for BpfMap {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("BpfMap").finish()
}
}
impl BpfMap {
pub fn new(unified_map: UnifiedMap, poll_ready: Arc<PollSetWrapper>) -> Self {
BpfMap {
unified_map: SpinNoPreempt::new(unified_map),
poll_ready,
}
}
pub fn unified_map(&self) -> SpinNoPreemptGuard<'_, UnifiedMap> {
self.unified_map.lock()
}
}
impl Pollable for BpfMap {
fn poll(&self) -> axpoll::IoEvents {
let map = self.unified_map();
let mut events = axpoll::IoEvents::empty();
if map.map().readable() {
events |= axpoll::IoEvents::IN;
}
if map.map().writable() {
events |= axpoll::IoEvents::OUT;
}
events
}
fn register(&self, context: &mut core::task::Context<'_>, _events: axpoll::IoEvents) {
self.poll_ready.register(context.waker());
}
}
impl FileLike for BpfMap {
fn read(&self, _dst: &mut crate::file::IoDst) -> AxResult<usize> {
Err(AxError::Unsupported)
}
fn write(&self, _src: &mut crate::file::IoSrc) -> AxResult<usize> {
Err(AxError::Unsupported)
}
fn stat(&self) -> AxResult<Kstat> {
Ok(Kstat::default())
}
fn path(&self) -> Cow<'_, str> {
"anon_inode:[bpf_map]".into()
}
}
pub struct PollSetWrapper(PollSet);
impl PollSetWrapper {
pub fn new() -> Self {
Self(PollSet::new())
}
}
impl Default for PollSetWrapper {
fn default() -> Self {
Self::new()
}
}
impl Deref for PollSetWrapper {
type Target = PollSet;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for PollSetWrapper {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl PollWaker for PollSetWrapper {
fn wake_up(&self) {
self.0.wake();
}
}
pub fn create_map(meta: BpfMapMeta) -> kbpf_basic::BpfResult<BpfMap> {
let waker = Arc::new(PollSetWrapper::new());
let waker_dyn: Arc<dyn PollWaker> = waker.clone();
let map = bpf_map_create::<EbpfKernelAuxiliary, PerCpuImpl>(meta, Some(waker_dyn))?;
Ok(BpfMap::new(map, waker))
}