mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-19 20:46:35 +00:00
Enable softirq mechanism
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
c02eacd50c
commit
558248a070
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -54,6 +54,12 @@ dependencies = [
|
|||||||
"spinning_top",
|
"spinning_top",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "array-init"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@ -102,6 +108,7 @@ dependencies = [
|
|||||||
"acpi",
|
"acpi",
|
||||||
"align_ext",
|
"align_ext",
|
||||||
"aml",
|
"aml",
|
||||||
|
"array-init",
|
||||||
"aster-main",
|
"aster-main",
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
|
@ -20,7 +20,8 @@ xarray = { git = "https://github.com/asterinas/xarray", rev = "72a4067" }
|
|||||||
int-to-c-enum = { path = "../../kernel/libs/int-to-c-enum" }
|
int-to-c-enum = { path = "../../kernel/libs/int-to-c-enum" }
|
||||||
# instrusive-collections of version 0.9.6 fails to compile with current rust toolchain,
|
# instrusive-collections of version 0.9.6 fails to compile with current rust toolchain,
|
||||||
# So we set a fixed version 0.9.5 for this crate
|
# So we set a fixed version 0.9.5 for this crate
|
||||||
intrusive-collections = "=0.9.5"
|
intrusive-collections = { version = "=0.9.5", features = ["nightly"] }
|
||||||
|
array-init = "2.0"
|
||||||
ktest = { path = "../libs/ktest" }
|
ktest = { path = "../libs/ktest" }
|
||||||
id-alloc = { path = "../libs/id-alloc" }
|
id-alloc = { path = "../libs/id-alloc" }
|
||||||
lazy_static = { version = "1.0", features = ["spin_no_std"] }
|
lazy_static = { version = "1.0", features = ["spin_no_std"] }
|
||||||
|
@ -18,11 +18,16 @@ pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame) {
|
|||||||
for callback_function in callback_functions.iter() {
|
for callback_function in callback_functions.iter() {
|
||||||
callback_function.call(trap_frame);
|
callback_function.call(trap_frame);
|
||||||
}
|
}
|
||||||
|
drop(callback_functions);
|
||||||
|
|
||||||
if !CpuException::is_cpu_exception(trap_frame.trap_num as u16) {
|
if !CpuException::is_cpu_exception(trap_frame.trap_num as u16) {
|
||||||
crate::arch::interrupts_ack();
|
crate::arch::interrupts_ack();
|
||||||
}
|
}
|
||||||
|
|
||||||
IN_INTERRUPT_CONTEXT.store(false, Ordering::Release);
|
IN_INTERRUPT_CONTEXT.store(false, Ordering::Release);
|
||||||
|
|
||||||
|
crate::arch::irq::enable_local();
|
||||||
|
crate::trap::softirq::process_pending();
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_local! {
|
cpu_local! {
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
mod handler;
|
mod handler;
|
||||||
mod irq;
|
mod irq;
|
||||||
|
pub mod softirq;
|
||||||
|
|
||||||
pub use handler::in_interrupt_context;
|
pub use handler::in_interrupt_context;
|
||||||
|
pub use softirq::SoftIrqLine;
|
||||||
pub use trapframe::TrapFrame;
|
pub use trapframe::TrapFrame;
|
||||||
|
|
||||||
pub(crate) use self::handler::call_irq_callback_functions;
|
pub(crate) use self::handler::call_irq_callback_functions;
|
||||||
@ -15,4 +17,5 @@ pub(crate) fn init() {
|
|||||||
unsafe {
|
unsafe {
|
||||||
trapframe::init();
|
trapframe::init();
|
||||||
}
|
}
|
||||||
|
softirq::init();
|
||||||
}
|
}
|
||||||
|
163
framework/aster-frame/src/trap/softirq.rs
Normal file
163
framework/aster-frame/src/trap/softirq.rs
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
|
||||||
|
|
||||||
|
use spin::Once;
|
||||||
|
|
||||||
|
use crate::{cpu_local, task::disable_preempt, CpuLocal};
|
||||||
|
|
||||||
|
/// A representation of a software interrupt (softirq) line.
|
||||||
|
///
|
||||||
|
/// # Overview
|
||||||
|
///
|
||||||
|
/// Softirq is an interrupt mechanism in the kernel that enables bottom-half processing;
|
||||||
|
/// they are cheaper to execute compared to regular interrupts because softirqs are less
|
||||||
|
/// time-critical and thus can be processed in a more flexible manner.
|
||||||
|
///
|
||||||
|
/// The `SoftIrqLine` struct encapsulates the data and functionality associated with each
|
||||||
|
/// softirq line, including an identifier and an associated callback that gets triggered
|
||||||
|
/// when the softirq is raised.
|
||||||
|
///
|
||||||
|
/// The `SoftIrqLine` with the smaller ID has the higher execution priority.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // Define an unused softirq id.
|
||||||
|
/// const MY_SOFTIRQ_ID: u8 = 4;
|
||||||
|
/// // Enable the softirq line of this id.
|
||||||
|
/// SoftIrqLine::get(MY_SOFTIRQ_ID).enable(|| {
|
||||||
|
/// // Define the action to take when the softirq with MY_SOFTIRQ_ID is raised
|
||||||
|
/// ...
|
||||||
|
/// });
|
||||||
|
/// // Later on:
|
||||||
|
/// SoftIrqLine::get(MY_SOFTIRQ_ID).raise(); // This will trigger the registered callback
|
||||||
|
/// ```
|
||||||
|
pub struct SoftIrqLine {
|
||||||
|
id: u8,
|
||||||
|
callback: Once<Box<dyn Fn() + 'static + Sync + Send>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SoftIrqLine {
|
||||||
|
/// The number of softirq lines.
|
||||||
|
const NR_LINES: u8 = 8;
|
||||||
|
|
||||||
|
/// Gets a softirq line.
|
||||||
|
///
|
||||||
|
/// The value of `id` must be within `0..NR_LINES`.
|
||||||
|
pub fn get(id: u8) -> &'static SoftIrqLine {
|
||||||
|
&LINES.get().unwrap()[id as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn new(id: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
callback: Once::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the ID of this softirq line.
|
||||||
|
pub fn id(&self) -> u8 {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raises the softirq, marking it as pending.
|
||||||
|
///
|
||||||
|
/// If this line is not enabled yet, the method has no effect.
|
||||||
|
pub fn raise(&self) {
|
||||||
|
CpuLocal::borrow_with(&PENDING_MASK, |mask| {
|
||||||
|
mask.fetch_or(1 << self.id, Ordering::Release);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables a softirq line by registering its callback.
|
||||||
|
///
|
||||||
|
/// # Panic
|
||||||
|
///
|
||||||
|
/// Each softirq can only be enabled once.
|
||||||
|
pub fn enable<F>(&self, callback: F)
|
||||||
|
where
|
||||||
|
F: Fn() + 'static + Sync + Send,
|
||||||
|
{
|
||||||
|
assert!(!self.is_enabled());
|
||||||
|
|
||||||
|
self.callback.call_once(|| Box::new(callback));
|
||||||
|
ENABLED_MASK.fetch_or(1 << self.id, Ordering::Release);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this softirq line is enabled.
|
||||||
|
pub fn is_enabled(&self) -> bool {
|
||||||
|
ENABLED_MASK.load(Ordering::Acquire) & (1 << self.id) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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();
|
||||||
|
|
||||||
|
pub(super) fn init() {
|
||||||
|
let lines: [SoftIrqLine; SoftIrqLine::NR_LINES as usize] =
|
||||||
|
array_init::array_init(|i| SoftIrqLine::new(i as u8));
|
||||||
|
LINES.call_once(|| lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ENABLED_MASK: AtomicU8 = AtomicU8::new(0);
|
||||||
|
|
||||||
|
cpu_local! {
|
||||||
|
static PENDING_MASK: AtomicU8 = AtomicU8::new(0);
|
||||||
|
static IS_ENABLED: AtomicBool = AtomicBool::new(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables softirq in current processor.
|
||||||
|
fn enable_softirq_local() {
|
||||||
|
CpuLocal::borrow_with(&IS_ENABLED, |is_enabled| {
|
||||||
|
is_enabled.store(true, Ordering::Release)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disables softirq in current processor.
|
||||||
|
fn disable_softirq_local() {
|
||||||
|
CpuLocal::borrow_with(&IS_ENABLED, |is_enabled| {
|
||||||
|
is_enabled.store(false, Ordering::Release)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks whether the softirq is enabled in current processor.
|
||||||
|
fn is_softirq_enabled() -> bool {
|
||||||
|
CpuLocal::borrow_with(&IS_ENABLED, |is_enabled| is_enabled.load(Ordering::Acquire))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Processes pending softirqs.
|
||||||
|
///
|
||||||
|
/// The processing instructions will iterate for `SOFTIRQ_RUN_TIMES` times. If any softirq
|
||||||
|
/// is raised during the iteration, it will be processed.
|
||||||
|
pub(crate) fn process_pending() {
|
||||||
|
const SOFTIRQ_RUN_TIMES: u8 = 5;
|
||||||
|
|
||||||
|
if !is_softirq_enabled() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let preempt_guard = disable_preempt();
|
||||||
|
disable_softirq_local();
|
||||||
|
|
||||||
|
CpuLocal::borrow_with(&PENDING_MASK, |mask| {
|
||||||
|
for i in 0..SOFTIRQ_RUN_TIMES {
|
||||||
|
// will not reactive in this handling.
|
||||||
|
let mut action_mask = {
|
||||||
|
let pending_mask = mask.fetch_and(0, Ordering::Acquire);
|
||||||
|
pending_mask & ENABLED_MASK.load(Ordering::Acquire)
|
||||||
|
};
|
||||||
|
|
||||||
|
if action_mask == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while action_mask > 0 {
|
||||||
|
let action_id = u8::trailing_zeros(action_mask) as u8;
|
||||||
|
SoftIrqLine::get(action_id).callback.get().unwrap()();
|
||||||
|
action_mask &= action_mask - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
enable_softirq_local();
|
||||||
|
}
|
13
kernel/aster-nix/src/softirq_id.rs
Normal file
13
kernel/aster-nix/src/softirq_id.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Defines the used IDs of software interrupt (softirq) lines.
|
||||||
|
|
||||||
|
/// The corresponding softirq line is used to schedule urgent taskless jobs.
|
||||||
|
pub const TASKLESS_URGENT_SOFTIRQ_ID: u8 = 0;
|
||||||
|
|
||||||
|
/// The corresponding softirq line is used to manage timers and handle
|
||||||
|
/// time-related jobs.
|
||||||
|
pub const TIMER_SOFTIRQ_ID: u8 = 1;
|
||||||
|
|
||||||
|
/// The corresponding softirq line is used to schedule general taskless jobs.
|
||||||
|
pub const TASKLESS_SOFTIRQ_ID: u8 = 2;
|
@ -3,17 +3,14 @@
|
|||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
use aster_frame::{
|
use aster_frame::{arch::timer::Jiffies, cpu_local, sync::SpinLock, CpuLocal};
|
||||||
arch::timer::{self, Jiffies},
|
|
||||||
cpu_local,
|
|
||||||
sync::SpinLock,
|
|
||||||
CpuLocal,
|
|
||||||
};
|
|
||||||
use aster_time::read_monotonic_time;
|
use aster_time::read_monotonic_time;
|
||||||
use paste::paste;
|
use paste::paste;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
use crate::time::{system_time::START_TIME_AS_DURATION, timer::TimerManager, Clock, SystemTime};
|
use crate::time::{
|
||||||
|
self, system_time::START_TIME_AS_DURATION, timer::TimerManager, Clock, SystemTime,
|
||||||
|
};
|
||||||
|
|
||||||
/// The Clock that reads the jiffies, and turn the counter into `Duration`.
|
/// The Clock that reads the jiffies, and turn the counter into `Duration`.
|
||||||
pub struct JiffiesClock {
|
pub struct JiffiesClock {
|
||||||
@ -220,7 +217,7 @@ macro_rules! define_timer_managers {
|
|||||||
let callback = move || {
|
let callback = move || {
|
||||||
clock_manager.process_expired_timers();
|
clock_manager.process_expired_timers();
|
||||||
};
|
};
|
||||||
timer::register_callback(callback);
|
time::softirq::register_callback(callback);
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,7 +255,7 @@ fn init_jiffies_clock_manager() {
|
|||||||
let callback = move || {
|
let callback = move || {
|
||||||
jiffies_timer_manager.process_expired_timers();
|
jiffies_timer_manager.process_expired_timers();
|
||||||
};
|
};
|
||||||
timer::register_callback(callback);
|
time::softirq::register_callback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_coarse_clock() {
|
fn update_coarse_clock() {
|
||||||
@ -270,7 +267,7 @@ fn update_coarse_clock() {
|
|||||||
fn init_coarse_clock() {
|
fn init_coarse_clock() {
|
||||||
let real_time = RealTimeClock::get().read_time();
|
let real_time = RealTimeClock::get().read_time();
|
||||||
RealTimeCoarseClock::current_ref().call_once(|| SpinLock::new(real_time));
|
RealTimeCoarseClock::current_ref().call_once(|| SpinLock::new(real_time));
|
||||||
timer::register_callback(update_coarse_clock);
|
time::softirq::register_callback(update_coarse_clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn init() {
|
pub(super) fn init() {
|
||||||
|
@ -12,6 +12,7 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
pub mod clocks;
|
pub mod clocks;
|
||||||
mod core;
|
mod core;
|
||||||
|
mod softirq;
|
||||||
mod system_time;
|
mod system_time;
|
||||||
pub mod wait;
|
pub mod wait;
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ pub type clock_t = i64;
|
|||||||
pub(super) fn init() {
|
pub(super) fn init() {
|
||||||
system_time::init();
|
system_time::init();
|
||||||
clocks::init();
|
clocks::init();
|
||||||
|
softirq::init();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
34
kernel/aster-nix/src/time/softirq.rs
Normal file
34
kernel/aster-nix/src/time/softirq.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
|
|
||||||
|
use aster_frame::{arch::timer, sync::RwLock, trap::SoftIrqLine};
|
||||||
|
|
||||||
|
use crate::softirq_id::TIMER_SOFTIRQ_ID;
|
||||||
|
|
||||||
|
static TIMER_SOFTIRQ_CALLBACKS: RwLock<Vec<Box<dyn Fn() + Sync + Send>>> = RwLock::new(Vec::new());
|
||||||
|
|
||||||
|
pub(super) fn init() {
|
||||||
|
SoftIrqLine::get(TIMER_SOFTIRQ_ID).enable(timer_softirq_handler);
|
||||||
|
|
||||||
|
timer::register_callback(|| {
|
||||||
|
SoftIrqLine::get(TIMER_SOFTIRQ_ID).raise();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers a function that will be executed during timer softirq.
|
||||||
|
pub(super) fn register_callback<F>(func: F)
|
||||||
|
where
|
||||||
|
F: Fn() + Sync + Send + 'static,
|
||||||
|
{
|
||||||
|
TIMER_SOFTIRQ_CALLBACKS
|
||||||
|
.write_irq_disabled()
|
||||||
|
.push(Box::new(func));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timer_softirq_handler() {
|
||||||
|
let callbacks = TIMER_SOFTIRQ_CALLBACKS.read_irq_disabled();
|
||||||
|
for callback in callbacks.iter() {
|
||||||
|
(callback)();
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user