From d6e40933b8b8cfe91a6b529631b79dbeb53ac99c Mon Sep 17 00:00:00 2001 From: Ruihan Li Date: Tue, 15 Apr 2025 22:22:07 +0800 Subject: [PATCH] Move the log lock to a better location --- kernel/comps/logger/src/aster_logger.rs | 6 ---- kernel/comps/logger/src/console.rs | 42 +++++++++++++++---------- ostd/src/arch/riscv/serial.rs | 20 ------------ ostd/src/arch/x86/serial.rs | 20 ------------ ostd/src/console.rs | 24 ++++++++++++-- ostd/src/logger.rs | 7 ----- 6 files changed, 46 insertions(+), 73 deletions(-) diff --git a/kernel/comps/logger/src/aster_logger.rs b/kernel/comps/logger/src/aster_logger.rs index 126292eef..e92f15cd3 100644 --- a/kernel/comps/logger/src/aster_logger.rs +++ b/kernel/comps/logger/src/aster_logger.rs @@ -15,12 +15,6 @@ impl log::Log for AsterLogger { fn log(&self, record: &Record) { let timestamp = Jiffies::elapsed().as_duration().as_secs_f64(); - - // Use a global lock to prevent interleaving of log messages. - use ostd::sync::SpinLock; - static RECORD_LOCK: SpinLock<()> = SpinLock::new(()); - let _lock = RECORD_LOCK.disable_irq().lock(); - print_logs(record, timestamp); } diff --git a/kernel/comps/logger/src/console.rs b/kernel/comps/logger/src/console.rs index d0402d6c3..73eca8ef4 100644 --- a/kernel/comps/logger/src/console.rs +++ b/kernel/comps/logger/src/console.rs @@ -5,26 +5,34 @@ //! FIXME: It will print to all `virtio-console` devices, which is not a good choice. //! -use core::fmt::{Arguments, Write}; +use alloc::{collections::btree_map::BTreeMap, fmt, string::String, sync::Arc}; +use core::fmt::Write; -struct VirtioConsolesPrinter; - -impl Write for VirtioConsolesPrinter { - fn write_str(&mut self, s: &str) -> core::fmt::Result { - // We must call `all_devices_lock` instead of `all_devices` here, as `all_devices` invokes - // the clone method of String and Arc, which may lead to a deadlock when there is low memory - // in the heap (The heap allocator will log a message when memory is low.). - let devices = aster_console::all_devices_lock(); - for (_, device) in devices.iter() { - device.send(s.as_bytes()); - } - Ok(()) - } -} +use aster_console::AnyConsoleDevice; +use ostd::sync::{LocalIrqDisabled, SpinLockGuard}; /// Prints the formatted arguments to the standard output. -pub fn _print(args: Arguments) { - VirtioConsolesPrinter.write_fmt(args).unwrap(); +pub fn _print(args: fmt::Arguments) { + // We must call `all_devices_lock` instead of `all_devices` here, as `all_devices` invokes the + // `clone` method of `String` and `Arc`, which may lead to a deadlock when there is low memory + // in the heap. (The heap allocator will log a message when memory is low.) + // + // Also, holding the lock will prevent the logs from interleaving. + let devices = aster_console::all_devices_lock(); + + struct Printer<'a>( + SpinLockGuard<'a, BTreeMap>, LocalIrqDisabled>, + ); + impl Write for Printer<'_> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.0 + .values() + .for_each(|console| console.send(s.as_bytes())); + Ok(()) + } + } + + Printer(devices).write_fmt(args).unwrap(); } /// Copied from Rust std: diff --git a/ostd/src/arch/riscv/serial.rs b/ostd/src/arch/riscv/serial.rs index b27d70ce4..985c6ad64 100644 --- a/ostd/src/arch/riscv/serial.rs +++ b/ostd/src/arch/riscv/serial.rs @@ -2,26 +2,6 @@ //! The console I/O. -use alloc::fmt; -use core::fmt::Write; - -/// Prints the formatted arguments to the standard output using the serial port. -#[inline] -pub fn print(args: fmt::Arguments) { - Stdout.write_fmt(args).unwrap(); -} - -struct Stdout; - -impl Write for Stdout { - fn write_str(&mut self, s: &str) -> fmt::Result { - for &c in s.as_bytes() { - send(c); - } - Ok(()) - } -} - /// Initializes the serial port. pub(crate) fn init() {} diff --git a/ostd/src/arch/x86/serial.rs b/ostd/src/arch/x86/serial.rs index 67f2f5557..6b66bb332 100644 --- a/ostd/src/arch/x86/serial.rs +++ b/ostd/src/arch/x86/serial.rs @@ -2,29 +2,9 @@ //! The console I/O. -use alloc::fmt; -use core::fmt::Write; - use super::device::serial::SerialPort; use crate::io::reserve_io_port_range; -/// Prints the formatted arguments to the standard output using the serial port. -#[inline] -pub fn print(args: fmt::Arguments) { - Stdout.write_fmt(args).unwrap(); -} - -struct Stdout; - -impl Write for Stdout { - fn write_str(&mut self, s: &str) -> fmt::Result { - for &c in s.as_bytes() { - send(c); - } - Ok(()) - } -} - bitflags::bitflags! { struct LineSts: u8 { const INPUT_FULL = 1; diff --git a/ostd/src/console.rs b/ostd/src/console.rs index 98b7c75e2..64b303a95 100644 --- a/ostd/src/console.rs +++ b/ostd/src/console.rs @@ -2,16 +2,34 @@ //! Console output. -use core::fmt::Arguments; +use core::fmt::{self, Arguments, Write}; -use crate::if_tdx_enabled; +use crate::{ + if_tdx_enabled, + sync::{LocalIrqDisabled, SpinLock}, +}; + +struct Stdout; + +impl Write for Stdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + for &c in s.as_bytes() { + crate::arch::serial::send(c); + } + Ok(()) + } +} + +static STDOUT: SpinLock = SpinLock::new(Stdout); /// Prints formatted arguments to the console. pub fn early_print(args: Arguments) { if_tdx_enabled!({ + // Hold the lock to prevent the logs from interleaving. + let _guard = STDOUT.lock(); tdx_guest::print(args); } else { - crate::arch::serial::print(args); + STDOUT.lock().write_fmt(args).unwrap(); }); } diff --git a/ostd/src/logger.rs b/ostd/src/logger.rs index c21e1ecba..31a700d41 100644 --- a/ostd/src/logger.rs +++ b/ostd/src/logger.rs @@ -56,14 +56,7 @@ impl log::Log for Logger { }; // Default implementation. - let level = record.level(); - - // Use a global lock to prevent interleaving of log messages. - use crate::sync::SpinLock; - static RECORD_LOCK: SpinLock<()> = SpinLock::new(()); - let _lock = RECORD_LOCK.disable_irq().lock(); - crate::console::early_print(format_args!("{}: {}\n", level, record.args())); }