Skip to content

Commit

Permalink
modify axipi to support more callback functions, add "ipi" features t…
Browse files Browse the repository at this point in the history
…o necessary crates
  • Loading branch information
aarkegz committed Dec 18, 2024
1 parent 07f028c commit c39f87d
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 65 deletions.
17 changes: 9 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion api/arceos_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ multitask = ["axtask/multitask", "axsync/multitask", "axfeat/multitask"]
fs = ["dep:axfs", "dep:axdriver", "axfeat/fs"]
net = ["dep:axnet", "dep:axdriver", "axfeat/net"]
display = ["dep:axdisplay", "dep:axdriver", "axfeat/display"]
ipi = ["dep:axipi", "axfeat/ipi"]

myfs = ["axfeat/myfs"]

Expand All @@ -43,4 +44,4 @@ axdriver = { workspace = true, optional = true }
axfs = { workspace = true, optional = true }
axnet = { workspace = true, optional = true }
axdisplay = { workspace = true, optional = true }
axipi = { workspace = true }
axipi = { workspace = true, optional = true }
3 changes: 2 additions & 1 deletion api/arceos_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,6 @@ pub mod modules {
pub use axlog;
pub use axruntime;
pub use axsync;
pub use axipi;

#[cfg(feature = "alloc")]
pub use axalloc;
Expand All @@ -409,4 +408,6 @@ pub mod modules {
pub use axnet;
#[cfg(feature = "multitask")]
pub use axtask;
#[cfg(feature = "ipi")]
pub use axipi;
}
3 changes: 2 additions & 1 deletion api/axfeat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fp_simd = ["axhal/fp_simd"]

# Interrupts
irq = ["axhal/irq", "axruntime/irq", "axtask?/irq"]
ipi = ["axhal/ipi", "axruntime/ipi"]
ipi = ["axhal/ipi", "axruntime/ipi", "dep:axipi"]

# Memory
alloc = ["axalloc", "axruntime/alloc"]
Expand Down Expand Up @@ -80,3 +80,4 @@ axdisplay = { workspace = true, optional = true }
axsync = { workspace = true, optional = true }
axtask = { workspace = true, optional = true }
kspin = { version = "0.1", optional = true }
axipi = { workspace = true, optional = true }
1 change: 1 addition & 0 deletions api/axfeat/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//! - `fp_simd`: Enable floating point and SIMD support.
//! - Interrupts:
//! - `irq`: Enable interrupt handling support.
//! - `ipi`: Enable Inter-Processor Interrupts (IPIs).
//! - Memory
//! - `alloc`: Enable dynamic memory allocation.
//! - `alloc-tlsf`: Use the TLSF allocator.
Expand Down
2 changes: 1 addition & 1 deletion modules/axhal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ tls = ["alloc"]
rtc = ["x86_rtc", "riscv_goldfish", "arm_pl031"]
default = []
hv = ["paging", "cortex-a", "percpu/arm-el2", "page_table_entry/arm-el2", "arm_gicv2/el2", "dep:crate_interface"]
ipi = []
ipi = ["irq"]

[dependencies]
log = "=0.4.21"
Expand Down
52 changes: 52 additions & 0 deletions modules/axipi/src/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use alloc::{boxed::Box, sync::Arc};

/// A callback function that will be called when an [`IPIEvent`] is received and handled.
pub struct Callback(Box<dyn FnOnce()>);

impl Callback {
/// Create a new [`Callback`] with the given function.
pub fn new<F: FnOnce() + 'static>(callback: F) -> Self {
Self(Box::new(callback))
}

/// Call the callback function.
pub fn call(self) {
(self.0)()
}
}

impl<T: FnOnce() + 'static> From<T> for Callback {
fn from(callback: T) -> Self {
Self::new(callback)
}
}

/// A [`Callback`] that can be called multiple times. It's used for multicast IPI events.
#[derive(Clone)]
pub struct MulticastCallback(Arc<dyn Fn()>);

impl MulticastCallback {
/// Create a new [`MulticastCallback`] with the given function.
pub fn new<F: Fn() + 'static>(callback: F) -> Self {
Self(Arc::new(callback))
}

/// Convert the [`MulticastCallback`] into a [`Callback`].
pub fn into_unicast(self) -> Callback {
Callback(Box::new(move || {
(self.0)()
}))
}
}

impl<T: Fn() + 'static> From<T> for MulticastCallback {
fn from(callback: T) -> Self {
Self::new(callback)
}
}

/// An IPI event that is sent from a source CPU to the target CPU.
pub struct IPIEvent {
pub src_cpu_id: usize,
pub callback: Callback,
}
19 changes: 10 additions & 9 deletions modules/axipi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ use kspin::SpinNoIrq;
use axhal::cpu::this_cpu_id;
use axhal::irq::IPI_IRQ_NUM;

mod event;
mod queue;

use queue::IPIEventQueue;

pub use queue::{IPIEvent, IPIEventFn};
pub use event::*;

#[percpu::def_percpu]
static IPI_EVENT_QUEUE: LazyInit<SpinNoIrq<IPIEventQueue<IPIEventFn>>> = LazyInit::new();
static IPI_EVENT_QUEUE: LazyInit<SpinNoIrq<IPIEventQueue>> = LazyInit::new();

/// Initialize the per-CPU IPI event queue.
pub fn init() {
Expand All @@ -30,34 +30,35 @@ pub fn init() {
}

/// Sends an IPI event to the processor(s) specified by `dest_cpu`.
pub fn send_ipi_event_to_one(dest_cpu: usize, event: IPIEventFn) {
pub fn send_ipi_event_to_one<T: Into<Callback>>(dest_cpu: usize, callback: T) {
warn!("Send IPI event to CPU {}", dest_cpu);

unsafe { IPI_EVENT_QUEUE.remote_ref_raw(dest_cpu) }
.lock()
.push(this_cpu_id(), event);
.push(this_cpu_id(), callback.into());
axhal::irq::send_sgi_one(dest_cpu, IPI_IRQ_NUM);
}

/// Sends an IPI event to all processors except the current one.
pub fn send_ipi_event_to_all(event: IPIEventFn) {
pub fn send_ipi_event_to_all<T: Into<MulticastCallback>>(callback: T) {
let current_cpu_id = this_cpu_id();
let callback = callback.into();
for cpu_id in 0..axconfig::SMP {
if cpu_id != current_cpu_id {
unsafe { IPI_EVENT_QUEUE.remote_ref_raw(cpu_id) }
.lock()
.push(current_cpu_id, event.clone());
.push(current_cpu_id, callback.clone().into_unicast());
}
}
axhal::irq::send_sgi_all(IPI_IRQ_NUM);
}

pub fn ipi_handler() {
while let Some((src_cpu_id, event)) = unsafe { IPI_EVENT_QUEUE.current_ref_mut_raw() }
while let Some((src_cpu_id, callback)) = unsafe { IPI_EVENT_QUEUE.current_ref_mut_raw() }
.lock()
.pop_one()
{
warn!("Received IPI event from CPU {}", src_cpu_id);
event.callback();
callback.call();
}
}
59 changes: 15 additions & 44 deletions modules/axipi/src/queue.rs
Original file line number Diff line number Diff line change
@@ -1,79 +1,50 @@
use alloc::boxed::Box;
use alloc::collections::VecDeque;

use crate::{Callback, IPIEvent};

/// A queue of IPI events.
///
/// It internally uses a `VecDeque` to store the events, make it
/// possible to pop these events using FIFO order.
pub struct IPIEventQueue<E: IPIEvent> {
events: VecDeque<IPIEventWrapper<E>>,
}

/// A trait that all events must implement.
pub trait IPIEvent: 'static {
/// Callback function that will be called when the event is triggered.
fn callback(self);
pub struct IPIEventQueue {
events: VecDeque<IPIEvent>,
}

struct IPIEventWrapper<E> {
src_cpu_id: usize,
event: E,
}

impl<E: IPIEvent> IPIEventQueue<E> {
/// Creates a new empty timer list.
impl IPIEventQueue {
/// Create a new empty timer list.
pub fn new() -> Self {
Self {
events: VecDeque::new(),
}
}

/// Whether there is no event.
#[allow(dead_code)]
#[inline]
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}

pub fn push(&mut self, src_cpu_id: usize, event: E) {
self.events.push_back(IPIEventWrapper { src_cpu_id, event });
/// Push a new event into the queue.
pub fn push(&mut self, src_cpu_id: usize, callback: Callback) {
self.events.push_back(IPIEvent { src_cpu_id, callback });
}

/// Try to pop the latest event that exists in the queue.
///
/// Returns `None` if no event is available.
pub fn pop_one(&mut self) -> Option<(usize, E)> {
/// Return `None` if no event is available.
#[must_use]
pub fn pop_one(&mut self) -> Option<(usize, Callback)> {
if let Some(e) = self.events.pop_front() {
Some((e.src_cpu_id, e.event))
Some((e.src_cpu_id, e.callback))
} else {
None
}
}
}

impl<E: IPIEvent> Default for IPIEventQueue<E> {
impl Default for IPIEventQueue {
fn default() -> Self {
Self::new()
}
}

/// A simple wrapper of a closure that implements the [`IPIEvent`] trait.
///
/// So that it can be used as in the [`IPIEventQueue`].
#[derive(Clone)]
pub struct IPIEventFn(Box<&'static dyn Fn()>);

impl IPIEventFn {
/// Constructs a new [`IPIEventFn`] from a closure.
pub fn new<F>(f: &'static F) -> Self
where
F: Fn(),
{
Self(Box::new(f))
}
}

impl IPIEvent for IPIEventFn {
fn callback(self) {
(self.0)()
}
}
1 change: 1 addition & 0 deletions ulib/axstd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ fp_simd = ["axfeat/fp_simd"]

# Interrupts
irq = ["arceos_api/irq", "axfeat/irq"]
ipi = ["arceos_api/ipi", "axfeat/ipi"]

# Memory
alloc = ["arceos_api/alloc", "axfeat/alloc", "axio/alloc"]
Expand Down

0 comments on commit c39f87d

Please sign in to comment.