os/log/
entry.rs

1//! 日志条目结构和序列化
2//!
3//! 该模块定义了表示单个日志消息及其元数据的 `LogEntry` 结构体,
4//! 并提供了用于创建和格式化日志条目的实用程序。
5
6use super::config::MAX_LOG_MESSAGE_LENGTH;
7use super::level::LogLevel;
8use core::cmp::min;
9use core::fmt::{self, Write};
10use core::sync::atomic::{AtomicUsize, Ordering};
11
12/// 带有元数据和消息的单个日志条目
13///
14/// 该结构体经过精心布局,用于无锁同步:
15/// - `seq` 字段用作生产者和消费者之间的**同步点**
16/// - 带有 8 字节对齐的 C 表示形式确保了正确的**原子访问**
17/// - 字段顺序经过优化以**最小化填充**
18#[repr(C, align(8))]
19#[derive(Debug)]
20pub struct LogEntry {
21    /// 用于同步的序列号(必须是第一个字段)
22    seq: AtomicUsize,
23    /// 日志级别 (Emergency, Error, Info, 等)
24    level: LogLevel,
25    /// 生成此日志的 CPU ID
26    cpu_id: usize,
27    /// 消息的实际长度(以字节为单位)
28    length: usize,
29    /// 生成此日志的任务/进程 ID
30    task_id: u32,
31    /// 创建日志时的时间戳
32    timestamp: usize,
33    /// 用于日志消息的固定大小缓冲区
34    message: [u8; MAX_LOG_MESSAGE_LENGTH],
35}
36
37impl LogEntry {
38    /// 创建一个空的日志条目(用于初始化)
39    ///
40    /// 这是一个 `const fn`,因此可以在编译时进行评估,
41    /// 允许对全局缓冲区进行常数初始化。
42    pub const fn empty() -> Self {
43        Self {
44            seq: AtomicUsize::new(0),
45            level: LogLevel::Debug,
46            cpu_id: 0,
47            length: 0,
48            task_id: 0,
49            timestamp: 0,
50            message: [0; MAX_LOG_MESSAGE_LENGTH],
51        }
52    }
53
54    /// 从格式化参数创建日志条目
55    ///
56    /// # 参数
57    ///
58    /// * `level` - 日志级别
59    /// * `cpu_id` - 生成日志的 CPU ID
60    /// * `task_id` - 生成日志的任务 ID
61    /// * `timestamp` - 日志的时间戳
62    /// * `args` - 来自 `format_args!` 宏的格式化参数
63    pub(super) fn from_args(
64        level: LogLevel,
65        cpu_id: usize,
66        task_id: u32,
67        timestamp: usize,
68        args: fmt::Arguments,
69    ) -> Self {
70        let mut entry = Self {
71            seq: AtomicUsize::new(0),
72            level,
73            cpu_id,
74            length: 0,
75            task_id,
76            timestamp,
77            message: [0; MAX_LOG_MESSAGE_LENGTH],
78        };
79
80        // 将消息格式化到固定大小的缓冲区中
81        let mut writer = MessageWriter::new(&mut entry.message);
82        let _ = core::fmt::write(&mut writer, args);
83
84        entry.length = writer.len();
85
86        entry
87    }
88
89    /// 将日志消息作为字符串切片返回
90    pub fn message(&self) -> &str {
91        // Safety: MessageWriter 确保了有效的 UTF-8
92        unsafe { core::str::from_utf8_unchecked(&self.message[..self.length]) }
93    }
94
95    /// 返回日志级别
96    pub fn level(&self) -> LogLevel {
97        self.level
98    }
99
100    /// 返回生成此日志的 CPU ID
101    pub fn cpu_id(&self) -> usize {
102        self.cpu_id
103    }
104
105    /// 返回生成此日志的任务 ID
106    pub fn task_id(&self) -> u32 {
107        self.task_id
108    }
109
110    /// 返回此日志的时间戳
111    pub fn timestamp(&self) -> usize {
112        self.timestamp
113    }
114}
115
116impl LogEntry {
117    /// 将日志数据复制到缓冲区槽中(供内部使用)
118    ///
119    /// 复制除 `seq` 字段外的所有字段,`seq` 字段必须
120    /// 通过 `publish()` 单独设置,以确保正确的内存顺序。
121    ///
122    /// # 安全性
123    ///
124    /// `dest` 必须指向环形缓冲区中有效的 `LogEntry`
125    pub(super) unsafe fn copy_data_to(&self, dest: *mut LogEntry) {
126        // 我们不能使用 ptr::write,因为它会覆盖 dest.seq
127        // 我们必须逐个字段复制,**除了** seq
128        unsafe {
129            (*dest).level = self.level;
130            (*dest).cpu_id = self.cpu_id;
131            (*dest).length = self.length;
132            (*dest).task_id = self.task_id;
133            (*dest).timestamp = self.timestamp;
134            (*dest).message.copy_from_slice(&self.message);
135        }
136    }
137
138    /// 通过设置其序列号来发布条目(供内部使用)
139    ///
140    /// 使用 **Release** 内存顺序,以确保在序列号更新之前,
141    /// 所有数据写入对其他核心都是可见的。
142    ///
143    /// # 安全性
144    ///
145    /// `dest` 必须指向环形缓冲区中有效的 `LogEntry`
146    pub(super) unsafe fn publish(&self, dest: *mut LogEntry, seq_num: usize) {
147        // 使用 Release 内存顺序,以确保在 'seq' 更新之前
148        // 所有数据写入都是可见的
149        unsafe {
150            (*dest).seq.store(seq_num, Ordering::Release);
151        }
152    }
153
154    /// 检查槽是否已准备好读取(供内部使用)
155    ///
156    /// 使用 **Acquire** 内存顺序与生产者在 `publish()` 中的 Release 存储配对,
157    /// 确保正确的同步。
158    ///
159    /// # 安全性
160    ///
161    /// `slot_ptr` 必须指向环形缓冲区中有效的 `LogEntry`
162    pub(super) unsafe fn is_ready(&self, slot_ptr: *const LogEntry, expected_seq: usize) -> bool {
163        // 使用 Acquire 内存顺序与生产者的 Release 存储配对
164        unsafe { (*slot_ptr).seq.load(Ordering::Acquire) == expected_seq }
165    }
166}
167
168impl Clone for LogEntry {
169    fn clone(&self) -> Self {
170        Self {
171            seq: AtomicUsize::new(self.seq.load(Ordering::Relaxed)),
172            level: self.level,
173            cpu_id: self.cpu_id,
174            length: self.length,
175            task_id: self.task_id,
176            timestamp: self.timestamp,
177            message: self.message,
178        }
179    }
180}
181
182impl fmt::Display for LogEntry {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        write!(
185            f,
186            "[{:12}] [{}] [CPU{}/T{:3}] {}",
187            self.timestamp,
188            self.level.as_str(),
189            self.cpu_id,
190            self.task_id,
191            self.message()
192        )
193    }
194}
195
196/// 辅助结构体,用于将格式化输出写入固定大小的字节缓冲区
197///
198/// 实现了 `core::fmt::Write`,用于在没有动态分配的情况下捕获来自 `format_args!` 的格式化输出。
199/// 消息如果超出缓冲区大小则会被截断。
200struct MessageWriter<'a> {
201    buffer: &'a mut [u8],
202    pos: usize,
203}
204
205impl<'a> MessageWriter<'a> {
206    /// 使用给定缓冲区创建新的消息写入器
207    fn new(buffer: &'a mut [u8]) -> Self {
208        Self { buffer, pos: 0 }
209    }
210
211    /// 返回到目前为止写入的字节数
212    fn len(&self) -> usize {
213        self.pos
214    }
215}
216
217impl Write for MessageWriter<'_> {
218    /// 将字符串切片写入缓冲区,必要时截断
219    fn write_str(&mut self, s: &str) -> fmt::Result {
220        let bytes = s.as_bytes();
221        let remaining = self.buffer.get_mut(self.pos..).unwrap_or(&mut []);
222        let to_copy = min(bytes.len(), remaining.len());
223
224        remaining[..to_copy].copy_from_slice(&bytes[..to_copy]);
225        self.pos += to_copy;
226        Ok(())
227    }
228}