diff --git a/framework/aster-frame/src/cpu.rs b/framework/aster-frame/src/cpu.rs index 96a6ec98..f9823363 100644 --- a/framework/aster-frame/src/cpu.rs +++ b/framework/aster-frame/src/cpu.rs @@ -39,14 +39,14 @@ macro_rules! cpu_local { // multiple declarations ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => { - $(#[$attr])* $vis static $name: CpuLocal<$t> = unsafe { CpuLocal::new($init) }; + $(#[$attr])* $vis static $name: $crate::CpuLocal<$t> = unsafe { $crate::CpuLocal::new($init) }; $crate::cpu_local!($($rest)*); }; // single declaration ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => ( // TODO: reimplement cpu-local variable to support multi-core - $(#[$attr])* $vis static $name: CpuLocal<$t> = CpuLocal::new($init); + $(#[$attr])* $vis static $name: $crate::CpuLocal<$t> = $crate::CpuLocal::new($init); ); } diff --git a/framework/aster-frame/src/task/processor.rs b/framework/aster-frame/src/task/processor.rs index 90034ae7..486c67c4 100644 --- a/framework/aster-frame/src/task/processor.rs +++ b/framework/aster-frame/src/task/processor.rs @@ -4,7 +4,7 @@ use core::sync::atomic::AtomicUsize; use crate::cpu_local; use crate::sync::Mutex; -use crate::{cpu::CpuLocal, trap::disable_local}; +use crate::trap::disable_local; use core::sync::atomic::Ordering::Relaxed; diff --git a/framework/aster-frame/src/trap/handler.rs b/framework/aster-frame/src/trap/handler.rs index 43e53ac1..2b843a0c 100644 --- a/framework/aster-frame/src/trap/handler.rs +++ b/framework/aster-frame/src/trap/handler.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 -use crate::{arch::irq::IRQ_LIST, cpu::CpuException}; +use core::sync::atomic::{AtomicBool, Ordering}; + +use crate::{arch::irq::IRQ_LIST, cpu::CpuException, cpu_local}; #[cfg(feature = "intel_tdx")] use crate::arch::tdx_guest::{handle_virtual_exception, TdxTrapFrame}; @@ -71,6 +73,12 @@ extern "sysv64" fn trap_handler(f: &mut TrapFrame) { } pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame) { + // For x86 CPUs, interrupts are not re-entrant. Local interrupts will be disabled when + // an interrupt handler is called (Unless interrupts are re-enabled in an interrupt handler). + // + // FIXME: For arch that supports re-entrant interrupts, we may need to record nested level here. + IN_INTERRUPT_CONTEXT.store(true, Ordering::Release); + let irq_line = IRQ_LIST.get().unwrap().get(trap_frame.trap_num).unwrap(); let callback_functions = irq_line.callback_list(); for callback_function in callback_functions.iter() { @@ -79,4 +87,18 @@ pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame) { if !CpuException::is_cpu_exception(trap_frame.trap_num as u16) { crate::arch::interrupts_ack(); } + + IN_INTERRUPT_CONTEXT.store(false, Ordering::Release); +} + +cpu_local! { + static IN_INTERRUPT_CONTEXT: AtomicBool = AtomicBool::new(false); +} + +/// Returns whether we are in the interrupt context. +/// +/// FIXME: Here only hardware irq is taken into account. According to linux implementation, if +/// we are in softirq context, or bottom half is disabled, this function also returns true. +pub fn in_interrupt_context() -> bool { + IN_INTERRUPT_CONTEXT.load(Ordering::Acquire) } diff --git a/framework/aster-frame/src/trap/mod.rs b/framework/aster-frame/src/trap/mod.rs index e4717e64..00b77ae0 100644 --- a/framework/aster-frame/src/trap/mod.rs +++ b/framework/aster-frame/src/trap/mod.rs @@ -5,6 +5,7 @@ mod irq; pub(crate) use self::handler::call_irq_callback_functions; pub use self::irq::{disable_local, DisabledLocalIrqGuard, IrqCallbackFunction, IrqLine}; +pub use handler::in_interrupt_context; pub use trapframe::TrapFrame; pub(crate) fn init() { diff --git a/services/aster-nix/src/device/tty/line_discipline.rs b/services/aster-nix/src/device/tty/line_discipline.rs index 63117009..4e08361d 100644 --- a/services/aster-nix/src/device/tty/line_discipline.rs +++ b/services/aster-nix/src/device/tty/line_discipline.rs @@ -8,7 +8,7 @@ use crate::process::signal::{Pollee, Poller}; use crate::thread::work_queue::work_item::WorkItem; use crate::thread::work_queue::{submit_work_item, WorkPriority}; use alloc::format; -use aster_frame::trap::disable_local; +use aster_frame::trap::{disable_local, in_interrupt_context}; use ringbuf::{ring_buffer::RbBase, Rb, StaticRb}; use super::termio::{KernelTermios, WinSize, CC_C_CHAR}; @@ -122,7 +122,7 @@ impl LineDiscipline { // Raw mode if !termios.is_canonical_mode() { self.read_buffer.lock_irq_disabled().push_overwrite(ch); - self.update_readable_state_deferred(); + self.update_readable_state(); return; } @@ -156,7 +156,7 @@ impl LineDiscipline { self.current_line.lock_irq_disabled().push_char(ch); } - self.update_readable_state_deferred(); + self.update_readable_state(); } fn may_send_signal(&self, termios: &KernelTermios, ch: u8) -> bool { @@ -169,14 +169,31 @@ impl LineDiscipline { ch if ch == *termios.get_special_char(CC_C_CHAR::VQUIT) => KernelSignal::new(SIGQUIT), _ => return false, }; - // `kernel_signal()` may cause sleep, so only construct parameters here. - self.work_item_para.lock_irq_disabled().kernel_signal = Some(signal); + + if in_interrupt_context() { + // `kernel_signal()` may cause sleep, so only construct parameters here. + self.work_item_para.lock_irq_disabled().kernel_signal = Some(signal); + } else { + (self.send_signal)(signal); + } true } pub fn update_readable_state(&self) { let buffer = self.read_buffer.lock_irq_disabled(); + + if in_interrupt_context() { + // Add/Del events may sleep, so only construct parameters here. + if !buffer.is_empty() { + self.work_item_para.lock_irq_disabled().pollee_type = Some(PolleeType::Add); + } else { + self.work_item_para.lock_irq_disabled().pollee_type = Some(PolleeType::Del); + } + submit_work_item(self.work_item.clone(), WorkPriority::High); + return; + } + if !buffer.is_empty() { self.pollee.add_events(IoEvents::IN); } else { @@ -184,17 +201,6 @@ impl LineDiscipline { } } - fn update_readable_state_deferred(&self) { - let buffer = self.read_buffer.lock_irq_disabled(); - // add/del events may sleep, so only construct parameters here. - if !buffer.is_empty() { - self.work_item_para.lock_irq_disabled().pollee_type = Some(PolleeType::Add); - } else { - self.work_item_para.lock_irq_disabled().pollee_type = Some(PolleeType::Del); - } - submit_work_item(self.work_item.clone(), WorkPriority::High); - } - /// include all operations that may cause sleep, and processes by a work queue. fn update_readable_state_after(&self) { if let Some(signal) = self.work_item_para.lock_irq_disabled().kernel_signal.take() {