Use a separate lock in esp-println (#2567)

This commit is contained in:
Dániel Buga 2024-11-22 13:29:26 +01:00 committed by GitHub
parent b5775667b4
commit c1f0c134c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 60 additions and 32 deletions

View File

@ -4,7 +4,7 @@
#[cfg(feature = "critical-section")] #[cfg(feature = "critical-section")]
use critical_section::RestoreState; use critical_section::RestoreState;
use super::PrinterImpl; use super::{LockToken, PrinterImpl};
/// Global logger lock. /// Global logger lock.
#[cfg(feature = "critical-section")] #[cfg(feature = "critical-section")]
@ -74,7 +74,12 @@ unsafe impl defmt::Logger for Logger {
} }
unsafe fn flush() { unsafe fn flush() {
PrinterImpl::flush(); let token = unsafe {
// Safety: the implementation ensures this is only called in a critical
// section.
LockToken::conjure()
};
PrinterImpl::flush(token);
} }
unsafe fn write(bytes: &[u8]) { unsafe fn write(bytes: &[u8]) {
@ -85,5 +90,10 @@ unsafe impl defmt::Logger for Logger {
} }
fn do_write(bytes: &[u8]) { fn do_write(bytes: &[u8]) {
PrinterImpl::write_bytes_assume_cs(bytes) let token = unsafe {
// Safety: the above implementation ensures this is only called in a critical
// section.
LockToken::conjure()
};
PrinterImpl::write_bytes_in_cs(bytes, token)
} }

View File

@ -87,9 +87,9 @@ impl core::fmt::Write for Printer {
impl Printer { impl Printer {
/// Writes a byte slice to the configured output. /// Writes a byte slice to the configured output.
pub fn write_bytes(bytes: &[u8]) { pub fn write_bytes(bytes: &[u8]) {
with(|| { with(|token| {
PrinterImpl::write_bytes_assume_cs(bytes); PrinterImpl::write_bytes_in_cs(bytes, token);
PrinterImpl::flush(); PrinterImpl::flush(token);
}) })
} }
} }
@ -114,10 +114,10 @@ type PrinterImpl = auto_printer::Printer;
) )
))] ))]
mod auto_printer { mod auto_printer {
use super::with;
use crate::{ use crate::{
serial_jtag_printer::Printer as PrinterSerialJtag, serial_jtag_printer::Printer as PrinterSerialJtag,
uart_printer::Printer as PrinterUart, uart_printer::Printer as PrinterUart,
LockToken,
}; };
pub struct Printer; pub struct Printer;
@ -145,27 +145,19 @@ mod auto_printer {
unsafe { (USB_DEVICE_INT_RAW.read_volatile() & SOF_INT_MASK) != 0 } unsafe { (USB_DEVICE_INT_RAW.read_volatile() & SOF_INT_MASK) != 0 }
} }
pub fn write_bytes_assume_cs(bytes: &[u8]) { pub fn write_bytes_in_cs(bytes: &[u8], token: LockToken<'_>) {
if Self::use_jtag() { if Self::use_jtag() {
with(|| { PrinterSerialJtag::write_bytes_in_cs(bytes, token);
PrinterSerialJtag::write_bytes_assume_cs(bytes);
})
} else { } else {
with(|| { PrinterUart::write_bytes_in_cs(bytes, token);
PrinterUart::write_bytes_assume_cs(bytes);
})
} }
} }
pub fn flush() { pub fn flush(token: LockToken<'_>) {
if Self::use_jtag() { if Self::use_jtag() {
with(|| { PrinterSerialJtag::flush(token);
PrinterSerialJtag::flush();
})
} else { } else {
with(|| { PrinterUart::flush(token);
PrinterUart::flush();
})
} }
} }
} }
@ -198,6 +190,8 @@ mod auto_printer {
))] ))]
mod serial_jtag_printer { mod serial_jtag_printer {
use portable_atomic::{AtomicBool, Ordering}; use portable_atomic::{AtomicBool, Ordering};
use super::LockToken;
pub struct Printer; pub struct Printer;
#[cfg(feature = "esp32c3")] #[cfg(feature = "esp32c3")]
@ -256,7 +250,7 @@ mod serial_jtag_printer {
} }
impl Printer { impl Printer {
pub fn write_bytes_assume_cs(bytes: &[u8]) { pub fn write_bytes_in_cs(bytes: &[u8], _token: LockToken<'_>) {
if fifo_full() { if fifo_full() {
// The FIFO is full. Let's see if we can progress. // The FIFO is full. Let's see if we can progress.
@ -289,7 +283,7 @@ mod serial_jtag_printer {
} }
} }
pub fn flush() { pub fn flush(_token: LockToken<'_>) {
fifo_flush(); fifo_flush();
} }
} }
@ -297,11 +291,12 @@ mod serial_jtag_printer {
#[cfg(all(any(feature = "uart", feature = "auto"), feature = "esp32"))] #[cfg(all(any(feature = "uart", feature = "auto"), feature = "esp32"))]
mod uart_printer { mod uart_printer {
use super::LockToken;
const UART_TX_ONE_CHAR: usize = 0x4000_9200; const UART_TX_ONE_CHAR: usize = 0x4000_9200;
pub struct Printer; pub struct Printer;
impl Printer { impl Printer {
pub fn write_bytes_assume_cs(bytes: &[u8]) { pub fn write_bytes_in_cs(bytes: &[u8], _token: LockToken<'_>) {
for &b in bytes { for &b in bytes {
unsafe { unsafe {
let uart_tx_one_char: unsafe extern "C" fn(u8) -> i32 = let uart_tx_one_char: unsafe extern "C" fn(u8) -> i32 =
@ -311,15 +306,16 @@ mod uart_printer {
} }
} }
pub fn flush() {} pub fn flush(_token: LockToken<'_>) {}
} }
} }
#[cfg(all(any(feature = "uart", feature = "auto"), feature = "esp32s2"))] #[cfg(all(any(feature = "uart", feature = "auto"), feature = "esp32s2"))]
mod uart_printer { mod uart_printer {
use super::LockToken;
pub struct Printer; pub struct Printer;
impl Printer { impl Printer {
pub fn write_bytes_assume_cs(bytes: &[u8]) { pub fn write_bytes_in_cs(bytes: &[u8], _token: LockToken<'_>) {
// On ESP32-S2 the UART_TX_ONE_CHAR ROM-function seems to have some issues. // On ESP32-S2 the UART_TX_ONE_CHAR ROM-function seems to have some issues.
for chunk in bytes.chunks(64) { for chunk in bytes.chunks(64) {
for &b in chunk { for &b in chunk {
@ -338,7 +334,7 @@ mod uart_printer {
} }
} }
pub fn flush() {} pub fn flush(_token: LockToken<'_>) {}
} }
} }
@ -347,6 +343,7 @@ mod uart_printer {
not(any(feature = "esp32", feature = "esp32s2")) not(any(feature = "esp32", feature = "esp32s2"))
))] ))]
mod uart_printer { mod uart_printer {
use super::LockToken;
trait Functions { trait Functions {
const TX_ONE_CHAR: usize; const TX_ONE_CHAR: usize;
const CHUNK_SIZE: usize = 32; const CHUNK_SIZE: usize = 32;
@ -459,7 +456,7 @@ mod uart_printer {
pub struct Printer; pub struct Printer;
impl Printer { impl Printer {
pub fn write_bytes_assume_cs(bytes: &[u8]) { pub fn write_bytes_in_cs(bytes: &[u8], _token: LockToken<'_>) {
for chunk in bytes.chunks(Device::CHUNK_SIZE) { for chunk in bytes.chunks(Device::CHUNK_SIZE) {
for &b in chunk { for &b in chunk {
Device::tx_byte(b); Device::tx_byte(b);
@ -469,15 +466,36 @@ mod uart_printer {
} }
} }
pub fn flush() {} pub fn flush(_token: LockToken<'_>) {}
} }
} }
#[cfg(not(feature = "critical-section"))]
type LockInner<'a> = PhantomData<&'a ()>;
#[cfg(feature = "critical-section")]
type LockInner<'a> = critical_section::CriticalSection<'a>;
#[derive(Clone, Copy)]
struct LockToken<'a>(LockInner<'a>);
impl<'a> LockToken<'a> {
#[allow(unused)]
unsafe fn conjure() -> Self {
#[cfg(feature = "critical-section")]
let inner = critical_section::CriticalSection::new();
#[cfg(not(feature = "critical-section"))]
let inner = PhantomData;
LockToken(inner)
}
}
/// Runs the callback in a critical section, if enabled.
#[inline] #[inline]
fn with<R>(f: impl FnOnce() -> R) -> R { fn with<R>(f: impl FnOnce(LockToken) -> R) -> R {
#[cfg(feature = "critical-section")] #[cfg(feature = "critical-section")]
return critical_section::with(|_| f()); return critical_section::with(|cs| f(LockToken(cs)));
#[cfg(not(feature = "critical-section"))] #[cfg(not(feature = "critical-section"))]
f() f(unsafe { LockToken::conjure() })
} }