以及以下宏:
macro_rules! log {
($verbosity: expr, $s: expr $(, $args: expr)*) => {
if $crate::logger::LOGGER.get_verbosity(module_path!()) <= $verbosity {
println_serial!("[{}] {}:{} {}", $verbosity, file!(), line!(), $s);
println_serial!($s $(, $args)*);
let log = $crate::logger::Log {
file: file!(),
line: line!(),
verbosity: $verbosity,
message: alloc::format!($s $(, $args)*)
};
$crate::logger::LOGGER.push_log(log); // this triggers a println_serial! call
}
}
}
我在一个工作的宏观上进行了调试!当我运行宏观如下时:
println_serial!
我得到以下输出:
log!(logger::Verbosity::Info, "Simple static string test");
Full脚本
[INFO] src/main.rs:83 Simple static string test
Simple static string test
logger.rs
use alloc::string::String;
use hashbrown::HashMap;
use crate::{
interrupts::guard::InterruptLock, util::circular_buffer::CircularBuffer,
};
macro_rules! log {
($verbosity: expr, $s: expr $(, $args: expr)*) => {
if $crate::logger::LOGGER.get_verbosity(module_path!()) <= $verbosity {
let log = $crate::logger::Log {
file: file!(),
line: line!(),
verbosity: $verbosity,
message: alloc::format!($s $(, $args)*)
};
$crate::logger::LOGGER.push_log(log);
}
}
}
pub static LOGGER: Logger = Logger::new();
pub struct Log {
pub file: &'static str,
pub line: u32,
pub verbosity: Verbosity,
pub message: String,
}
impl core::fmt::Display for Log {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_fmt(format_args!(
"[{}] {}:{} {}",
self.verbosity, self.file, self.line, self.message
))?;
Ok(())
}
}
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub enum Verbosity {
Debug,
Info,
Warning,
Error,
}
impl core::fmt::Display for Verbosity {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Debug => f.write_str("DEBUG"),
Self::Info => f.write_str("INFO"),
Self::Warning => f.write_str("WARNING"),
Self::Error => f.write_str("ERROR"),
}?;
Ok(())
}
}
pub struct Logger {
verbose: InterruptLock<Option<HashMap<String, Verbosity>>>,
logs: InterruptLock<CircularBuffer<Log, 1024>>,
}
impl Logger {
const fn new() -> Self {
Logger {
verbose: InterruptLock::new(None),
logs: InterruptLock::new(CircularBuffer::new()),
}
}
pub fn get_verbosity(&self, module: &str) -> Verbosity {
*self
.verbose
.lock()
.as_ref()
.expect("Logger not initialized")
.get(module)
.unwrap_or(&Verbosity::Info)
}
pub fn push_log(&self, log: Log) {
if self.logs.lock().push_back(log).is_err() {
panic!("Dropped log");
}
}
pub fn trigger(&self) {
while let Some(log) = self.logs.lock().pop_front() {
println_serial!("{}", log);
}
}
}
pub fn init(verbose: HashMap<String, Verbosity>) {
*LOGGER.verbose.lock() = Some(verbose);
}
pub fn trigger() {
LOGGER.trigger()
}
circular_buffer.rs
use core::mem::MaybeUninit;
use thiserror_no_std::Error;
#[derive(Error, Debug)]
#[error("Failed to push item into buffer")]
pub struct PushError;
pub struct CircularBuffer<T, const N: usize> {
array: [MaybeUninit<T>; N],
head: usize,
tail: usize,
}
impl<T, const N: usize> CircularBuffer<T, N> {
pub const fn new() -> Self {
Self {
array: MaybeUninit::uninit_array(),
head: 0,
tail: 0,
}
}
pub fn push_back(&mut self, item: T) -> Result<(), PushError> {
let insertion_index = self.tail;
match self.increment_tail() {
Some(tail) => self.tail = tail,
None => return Err(PushError),
}
self.array[insertion_index] = MaybeUninit::new(item);
Ok(())
}
pub fn pop_front(&mut self) -> Option<T> {
let index = self.head;
if self.head == self.tail {
return None;
}
wrapping_increment(&mut self.head, N);
if self.tail == N + 1 {
self.tail = index;
}
let mut ret = MaybeUninit::uninit();
core::mem::swap(&mut ret, &mut self.array[index]);
unsafe { Some(ret.assume_init()) }
}
fn increment_tail(&mut self) -> Option<usize> {
if self.tail == N + 1 {
return None;
}
wrapping_increment(&mut self.tail, N);
if self.tail == self.head {
self.tail = N + 1;
}
Some(self.tail)
}
}
fn wrapping_increment(i: &mut usize, container_size: usize) {
*i = (*i + 1) % container_size
}
guard.rs
use core::{
arch::asm,
cell::UnsafeCell,
ops::{Deref, DerefMut},
sync::atomic::{AtomicUsize, Ordering},
};
static NUM_GUARDS: AtomicUsize = AtomicUsize::new(0);
pub struct InterruptGuard<'a, T> {
data: &'a mut T,
}
impl<'a, T> Drop for InterruptGuard<'a, T> {
fn drop(&mut self) {
if NUM_GUARDS.fetch_sub(1, Ordering::SeqCst) == 1 {
unsafe {
asm!("sti");
}
}
}
}
impl<'a, T> Deref for InterruptGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
self.data
}
}
impl<'a, T> DerefMut for InterruptGuard<'a, T> {
fn deref_mut(&mut self) -> &mut T {
self.data
}
}
pub struct InterruptLock<T> {
data: UnsafeCell<T>,
}
impl<T> InterruptLock<T> {
pub const fn new(data: T) -> InterruptLock<T> {
InterruptLock {
data: UnsafeCell::new(data),
}
}
pub fn lock(&self) -> InterruptGuard<'_, T> {
NUM_GUARDS.fetch_add(1, Ordering::SeqCst);
unsafe {
asm!("cli");
}
unsafe {
InterruptGuard {
data: &mut *self.data.get(),
}
}
}
}
// NOTE: Sync implementation assumes single threaded os
unsafe impl<T> Sync for InterruptLock<T> {}
的输出。我希望宏仅通过使用其他宏来使用LOGGER
调用来工作。删除后,未能获得输出。
alloc::format!()
println_serial!
宏!我在一个领域工作
使用在主函数中调用的
push_log
函数调用所有记录。
println_serial!
函数从缓冲区弹出日志,并将其传递到
no_std
奇特的宏也可以与其他表达式一起工作(ex:
trigger
)PS:这是自定义内核项目的一部分,因此有很多代码。也很高兴也分享,我只是想我会分享核心位。
在大量挖掘后,问题与实现记录器的方式无关。该错误实际上是我的自定义内存分配器的实现方式,这就是为什么失败的原因。 在评论中为每个人的所有人致意,他们帮助我进一步完善了这个问题。