Move SoftIRQ implementations to softirq component

This commit is contained in:
Chen Chengjun 2024-10-17 17:41:24 +08:00 committed by Tate, Hongliang Tian
parent 54a807b5f7
commit 2f511069ee
17 changed files with 106 additions and 47 deletions

11
Cargo.lock generated
View File

@ -161,6 +161,7 @@ dependencies = [
"aster-network", "aster-network",
"aster-rights", "aster-rights",
"aster-rights-proc", "aster-rights-proc",
"aster-softirq",
"aster-time", "aster-time",
"aster-util", "aster-util",
"aster-virtio", "aster-virtio",
@ -218,6 +219,16 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "aster-softirq"
version = "0.1.0"
dependencies = [
"component",
"intrusive-collections",
"ostd",
"spin 0.9.8",
]
[[package]] [[package]]
name = "aster-time" name = "aster-time"
version = "0.1.0" version = "0.1.0"

View File

@ -16,6 +16,7 @@ members = [
"kernel/comps/framebuffer", "kernel/comps/framebuffer",
"kernel/comps/input", "kernel/comps/input",
"kernel/comps/network", "kernel/comps/network",
"kernel/comps/softirq",
"kernel/comps/time", "kernel/comps/time",
"kernel/comps/virtio", "kernel/comps/virtio",
"kernel/libs/cpio-decoder", "kernel/libs/cpio-decoder",

View File

@ -5,6 +5,7 @@ virtio = { name = "aster-virtio" }
input = { name = "aster-input" } input = { name = "aster-input" }
block = { name = "aster-block" } block = { name = "aster-block" }
console = { name = "aster-console" } console = { name = "aster-console" }
softirq = { name = "aster-softirq" }
time = { name = "aster-time" } time = { name = "aster-time" }
framebuffer = { name = "aster-framebuffer" } framebuffer = { name = "aster-framebuffer" }
network = { name = "aster-network" } network = { name = "aster-network" }

View File

@ -135,6 +135,7 @@ OSDK_CRATES := \
kernel/comps/framebuffer \ kernel/comps/framebuffer \
kernel/comps/input \ kernel/comps/input \
kernel/comps/network \ kernel/comps/network \
kernel/comps/softirq \
kernel/comps/time \ kernel/comps/time \
kernel/comps/virtio \ kernel/comps/virtio \
kernel/libs/aster-util \ kernel/libs/aster-util \

View File

@ -12,6 +12,7 @@ aster-block = { path = "comps/block" }
aster-network = { path = "comps/network" } aster-network = { path = "comps/network" }
aster-console = { path = "comps/console" } aster-console = { path = "comps/console" }
aster-framebuffer = { path = "comps/framebuffer" } aster-framebuffer = { path = "comps/framebuffer" }
aster-softirq = { path = "comps/softirq" }
aster-time = { path = "comps/time" } aster-time = { path = "comps/time" }
aster-virtio = { path = "comps/virtio" } aster-virtio = { path = "comps/virtio" }
aster-rights = { path = "libs/aster-rights" } aster-rights = { path = "libs/aster-rights" }

View File

@ -0,0 +1,14 @@
[package]
name = "aster-softirq"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
ostd = { path = "../../../ostd" }
component = { path = "../../libs/comp-sys/component" }
intrusive-collections = "0.9.5"
spin = "0.9.4"
[features]

View File

@ -1,13 +1,22 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! Software interrupt. //! Software interrupt.
#![no_std]
#![deny(unsafe_code)]
extern crate alloc;
use alloc::boxed::Box; use alloc::boxed::Box;
use core::sync::atomic::{AtomicU8, Ordering}; use core::sync::atomic::{AtomicU8, Ordering};
use component::{init_component, ComponentInitError};
use ostd::{cpu_local_cell, trap::register_bottom_half_handler};
use spin::Once; use spin::Once;
use crate::{cpu_local_cell, task::disable_preempt}; pub mod softirq_id;
mod taskless;
pub use taskless::Taskless;
/// A representation of a software interrupt (softirq) line. /// A representation of a software interrupt (softirq) line.
/// ///
@ -95,15 +104,15 @@ impl SoftIrqLine {
/// A slice that stores the [`SoftIrqLine`]s, whose ID is equal to its offset in the slice. /// A slice that stores the [`SoftIrqLine`]s, whose ID is equal to its offset in the slice.
static LINES: Once<[SoftIrqLine; SoftIrqLine::NR_LINES as usize]> = Once::new(); static LINES: Once<[SoftIrqLine; SoftIrqLine::NR_LINES as usize]> = Once::new();
/// Initializes the softirq lines. #[init_component]
/// fn init() -> Result<(), ComponentInitError> {
/// # Safety
///
/// This function must be called only once.
pub unsafe fn init() {
let lines: [SoftIrqLine; SoftIrqLine::NR_LINES as usize] = let lines: [SoftIrqLine; SoftIrqLine::NR_LINES as usize] =
core::array::from_fn(|i| SoftIrqLine::new(i as u8)); core::array::from_fn(|i| SoftIrqLine::new(i as u8));
LINES.call_once(|| lines); LINES.call_once(|| lines);
register_bottom_half_handler(process_pending);
taskless::init();
Ok(())
} }
static ENABLED_MASK: AtomicU8 = AtomicU8::new(0); static ENABLED_MASK: AtomicU8 = AtomicU8::new(0);
@ -139,7 +148,6 @@ pub(crate) fn process_pending() {
return; return;
} }
let _preempt_guard = disable_preempt();
disable_softirq_local(); disable_softirq_local();
for _i in 0..SOFTIRQ_RUN_TIMES { for _i in 0..SOFTIRQ_RUN_TIMES {

View File

@ -8,13 +8,12 @@ use core::{
}; };
use intrusive_collections::{intrusive_adapter, LinkedList, LinkedListAtomicLink}; use intrusive_collections::{intrusive_adapter, LinkedList, LinkedListAtomicLink};
use ostd::{ use ostd::{cpu::local::CpuLocal, cpu_local, trap};
cpu::local::CpuLocal,
cpu_local,
trap::{self, SoftIrqLine},
};
use crate::softirq_id::{TASKLESS_SOFTIRQ_ID, TASKLESS_URGENT_SOFTIRQ_ID}; use super::{
softirq_id::{TASKLESS_SOFTIRQ_ID, TASKLESS_URGENT_SOFTIRQ_ID},
SoftIrqLine,
};
/// `Taskless` represents a _taskless_ job whose execution is deferred to a later time. /// `Taskless` represents a _taskless_ job whose execution is deferred to a later time.
/// ///
@ -211,7 +210,7 @@ mod test {
fn init() { fn init() {
static DONE: AtomicBool = AtomicBool::new(false); static DONE: AtomicBool = AtomicBool::new(false);
if !DONE.load(Ordering::SeqCst) { if !DONE.load(Ordering::SeqCst) {
super::init(); let _ = super::super::init();
DONE.store(true, Ordering::SeqCst); DONE.store(true, Ordering::SeqCst);
} }
} }

View File

@ -70,9 +70,7 @@ pub mod net;
pub mod prelude; pub mod prelude;
mod process; mod process;
mod sched; mod sched;
pub mod softirq_id;
pub mod syscall; pub mod syscall;
mod taskless;
pub mod thread; pub mod thread;
pub mod time; pub mod time;
mod util; mod util;
@ -109,7 +107,6 @@ pub fn init() {
fs::rootfs::init(boot::initramfs()).unwrap(); fs::rootfs::init(boot::initramfs()).unwrap();
device::init().unwrap(); device::init().unwrap();
vdso::init(); vdso::init();
taskless::init();
process::init(); process::init();
} }

View File

@ -2,9 +2,8 @@
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
use ostd::{sync::RwLock, timer, trap::SoftIrqLine}; use aster_softirq::{softirq_id::TIMER_SOFTIRQ_ID, SoftIrqLine};
use ostd::{sync::RwLock, timer};
use crate::softirq_id::TIMER_SOFTIRQ_ID;
static TIMER_SOFTIRQ_CALLBACKS: RwLock<Vec<Box<dyn Fn() + Sync + Send>>> = RwLock::new(Vec::new()); static TIMER_SOFTIRQ_CALLBACKS: RwLock<Vec<Box<dyn Fn() + Sync + Send>>> = RwLock::new(Vec::new());

View File

@ -39,6 +39,7 @@ use crate::arch;
/// println!("2nd FOO VAL: {:?}", FOO.load()); /// println!("2nd FOO VAL: {:?}", FOO.load());
/// } /// }
/// ``` /// ```
#[macro_export]
macro_rules! cpu_local_cell { macro_rules! cpu_local_cell {
($( $(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; )*) => { ($( $(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; )*) => {
$( $(
@ -55,8 +56,6 @@ macro_rules! cpu_local_cell {
}; };
} }
pub(crate) use cpu_local_cell;
/// Inner mutable CPU-local objects. /// Inner mutable CPU-local objects.
/// ///
/// CPU-local cell objects are only accessible from the current CPU. When /// CPU-local cell objects are only accessible from the current CPU. When
@ -71,6 +70,10 @@ pub(crate) use cpu_local_cell;
/// You should only create the CPU-local cell object using the macro /// You should only create the CPU-local cell object using the macro
/// [`cpu_local_cell!`]. /// [`cpu_local_cell!`].
/// ///
/// Please exercise extreme caution when using `CpuLocalCell`. In most cases,
/// it is necessary to disable interrupts or preemption when using it to prevent
/// the operated object from being changed, which can lead to race conditions.
///
/// For the difference between [`super::CpuLocal`] and [`CpuLocalCell`], see /// For the difference between [`super::CpuLocal`] and [`CpuLocalCell`], see
/// [`super`]. /// [`super`].
pub struct CpuLocalCell<T: 'static>(UnsafeCell<T>); pub struct CpuLocalCell<T: 'static>(UnsafeCell<T>);

View File

@ -28,10 +28,6 @@
// the CPU-local objects can be shared across CPUs. While through a CPU-local // the CPU-local objects can be shared across CPUs. While through a CPU-local
// cell object you can only access the value on the current CPU, therefore // cell object you can only access the value on the current CPU, therefore
// enabling inner mutability without locks. // enabling inner mutability without locks.
//
// The cell-variant is currently not a public API because that it is rather
// hard to be used without introducing races. But it is useful for OSTD's
// internal implementation.
mod cell; mod cell;
mod cpu_local; mod cpu_local;
@ -41,7 +37,7 @@ pub(crate) mod single_instr;
use alloc::vec::Vec; use alloc::vec::Vec;
use align_ext::AlignExt; use align_ext::AlignExt;
pub(crate) use cell::{cpu_local_cell, CpuLocalCell}; pub use cell::CpuLocalCell;
pub use cpu_local::{CpuLocal, CpuLocalDerefGuard}; pub use cpu_local::{CpuLocal, CpuLocalDerefGuard};
use spin::Once; use spin::Once;

View File

@ -13,11 +13,11 @@ cfg_if::cfg_if! {
} }
use bitvec::prelude::BitVec; use bitvec::prelude::BitVec;
use local::cpu_local_cell;
use spin::Once; use spin::Once;
use crate::{ use crate::{
arch::boot::smp::get_num_processors, task::DisabledPreemptGuard, trap::DisabledLocalIrqGuard, arch::boot::smp::get_num_processors, cpu_local_cell, task::DisabledPreemptGuard,
trap::DisabledLocalIrqGuard,
}; };
/// The number of CPUs. /// The number of CPUs.

View File

@ -51,8 +51,6 @@ pub use ostd_macros::main;
pub use ostd_pod::Pod; pub use ostd_pod::Pod;
pub use self::{error::Error, prelude::Result}; pub use self::{error::Error, prelude::Result};
// [`CpuLocalCell`] is easy to be misused, so we don't expose it to the users.
pub(crate) use crate::cpu::local::cpu_local_cell;
/// Initializes OSTD. /// Initializes OSTD.
/// ///
@ -87,8 +85,6 @@ pub unsafe fn init() {
mm::kspace::init_kernel_page_table(mm::init_page_meta()); mm::kspace::init_kernel_page_table(mm::init_page_meta());
mm::dma::init(); mm::dma::init();
// SAFETY: This function is called only once in the entire system.
unsafe { trap::softirq::init() };
arch::init_on_bsp(); arch::init_on_bsp();
smp::init(); smp::init();

View File

@ -1,6 +1,47 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
use crate::{arch::irq::IRQ_LIST, cpu_local_cell, trap::TrapFrame}; use alloc::boxed::Box;
use spin::Once;
use crate::{arch::irq::IRQ_LIST, cpu_local_cell, task::disable_preempt, trap::TrapFrame};
static BOTTOM_HALF_HANDLER: Once<Box<dyn Fn() + Sync + Send>> = Once::new();
/// Register a function to the interrupt bottom half execution.
///
/// The handling of an interrupt can be divided into two parts: top half and bottom half.
/// Top half typically performs critical tasks and runs at a high priority.
/// Relatively, bottom half defers less critical tasks to reduce the time spent in
/// hardware interrupt context, thus allowing the interrupts to be handled more quickly.
///
/// The bottom half handler will be called after the top half with interrupts enabled.
///
/// This function can only be registered once. Subsequent calls will do nothing.
pub fn register_bottom_half_handler<F>(func: F)
where
F: Fn() + Sync + Send + 'static,
{
BOTTOM_HALF_HANDLER.call_once(|| Box::new(func));
}
fn process_top_half(trap_frame: &TrapFrame, irq_number: usize) {
let irq_line = IRQ_LIST.get().unwrap().get(irq_number).unwrap();
let callback_functions = irq_line.callback_list();
for callback_function in callback_functions.iter() {
callback_function.call(trap_frame);
}
}
fn process_bottom_half() {
// We need to disable preemption when processing bottom half since
// the interrupt is enabled in this context.
let _preempt_guard = disable_preempt();
if let Some(handler) = BOTTOM_HALF_HANDLER.get() {
handler()
}
}
pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame, irq_number: usize) { pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame, irq_number: usize) {
// For x86 CPUs, interrupts are not re-entrant. Local interrupts will be disabled when // For x86 CPUs, interrupts are not re-entrant. Local interrupts will be disabled when
@ -9,17 +50,10 @@ pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame, irq_number: us
// FIXME: For arch that supports re-entrant interrupts, we may need to record nested level here. // FIXME: For arch that supports re-entrant interrupts, we may need to record nested level here.
IN_INTERRUPT_CONTEXT.store(true); IN_INTERRUPT_CONTEXT.store(true);
let irq_line = IRQ_LIST.get().unwrap().get(irq_number).unwrap(); process_top_half(trap_frame, irq_number);
let callback_functions = irq_line.callback_list();
for callback_function in callback_functions.iter() {
callback_function.call(trap_frame);
}
drop(callback_functions);
crate::arch::interrupts_ack(irq_number); crate::arch::interrupts_ack(irq_number);
crate::arch::irq::enable_local(); crate::arch::irq::enable_local();
crate::trap::softirq::process_pending(); process_bottom_half();
IN_INTERRUPT_CONTEXT.store(false); IN_INTERRUPT_CONTEXT.store(false);
} }

View File

@ -4,10 +4,8 @@
mod handler; mod handler;
mod irq; mod irq;
pub mod softirq;
pub use handler::in_interrupt_context; pub use handler::{in_interrupt_context, register_bottom_half_handler};
pub use softirq::SoftIrqLine;
pub(crate) use self::handler::call_irq_callback_functions; pub(crate) use self::handler::call_irq_callback_functions;
pub use self::irq::{disable_local, DisabledLocalIrqGuard, IrqCallbackFunction, IrqLine}; pub use self::irq::{disable_local, DisabledLocalIrqGuard, IrqCallbackFunction, IrqLine};