mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-10 05:46:48 +00:00
Move SoftIRQ implementations to softirq component
This commit is contained in:
parent
54a807b5f7
commit
2f511069ee
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -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"
|
||||||
|
@ -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",
|
||||||
|
@ -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" }
|
||||||
|
1
Makefile
1
Makefile
@ -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 \
|
||||||
|
@ -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" }
|
||||||
|
14
kernel/comps/softirq/Cargo.toml
Normal file
14
kernel/comps/softirq/Cargo.toml
Normal 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]
|
@ -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 {
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
|
||||||
|
@ -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>);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user