Skip to main content

strat9_kernel/arch/x86_64/vga/
log_queue.rs

1//! Fixed-storage log queue. Safe publication under SMP and bounded overflow.
2use core::sync::atomic::{AtomicUsize, Ordering};
3use heapless::mpmc::Queue;
4
5pub const CAPACITY: usize = 512;
6pub const LINE_LEN: usize = 256;
7
8#[derive(Clone, Copy)]
9pub struct Line {
10    pub bytes: [u8; LINE_LEN],
11    pub len: usize,
12}
13
14impl Line {
15    pub const EMPTY: Self = Self {
16        bytes: [0; LINE_LEN],
17        len: 0,
18    };
19
20    pub fn as_bytes(&self) -> &[u8] {
21        &self.bytes[..self.len]
22    }
23}
24
25pub struct LogQueue {
26    queue: Queue<Line, CAPACITY>,
27    written: AtomicUsize,
28    dropped: AtomicUsize,
29}
30
31impl LogQueue {
32    // This lossy log sink permits transient enqueue failures and retries
33    // dequeue on the next display tick, as required by heapless::mpmc.
34    #[expect(deprecated, reason = "log drops and delayed dequeue are supported")]
35    pub const fn new() -> Self {
36        Self {
37            queue: Queue::new(),
38            written: AtomicUsize::new(0),
39            dropped: AtomicUsize::new(0),
40        }
41    }
42
43    pub fn push(&self, bytes: &[u8]) {
44        if bytes.is_empty() {
45            return;
46        }
47        let mut line = Line::EMPTY;
48        line.len = bytes.len().min(LINE_LEN - 1);
49        line.bytes[..line.len].copy_from_slice(&bytes[..line.len]);
50        if self.queue.enqueue(line).is_ok() {
51            self.written.fetch_add(1, Ordering::Relaxed);
52        } else {
53            self.dropped.fetch_add(1, Ordering::Relaxed);
54        }
55    }
56
57    pub fn pop(&self) -> Option<Line> {
58        self.queue.dequeue()
59    }
60    pub fn written(&self) -> usize {
61        self.written.load(Ordering::Relaxed)
62    }
63    pub fn dropped(&self) -> usize {
64        self.dropped.load(Ordering::Relaxed)
65    }
66}