diff --git a/kernel/rustkernel/src/console/uart.rs b/kernel/rustkernel/src/console/uart.rs index f4fb74c..b831e4d 100644 --- a/kernel/rustkernel/src/console/uart.rs +++ b/kernel/rustkernel/src/console/uart.rs @@ -1,7 +1,10 @@ //! Low-level driver routines for 16550a UART. #![allow(non_upper_case_globals)] -use crate::{console::consoleintr, proc::wakeup, sync::spinlock::Spinlock, trap::InterruptBlocker}; +use crate::{ + console::consoleintr, proc::wakeup, queue::Queue, sync::spinlock::Spinlock, + trap::InterruptBlocker, +}; use core::ptr::addr_of; // The UART control registers. @@ -22,8 +25,6 @@ const LSR_RX_READY: u8 = 1 << 0; /// THR can accept another character to send const LSR_TX_IDLE: u8 = 1 << 5; -const UART_TX_BUF_SIZE: usize = 32; - pub static UART0: Uart = Uart::new(crate::riscv::memlayout::UART0); enum Register { @@ -61,18 +62,14 @@ impl Register { pub struct Uart { pub lock: Spinlock, pub base_address: usize, - pub buffer: [u8; UART_TX_BUF_SIZE], - pub queue_start: usize, - pub queue_end: usize, + pub buffer: Queue, } impl Uart { pub const fn new(base_address: usize) -> Uart { Uart { lock: Spinlock::new(), base_address, - buffer: [0u8; UART_TX_BUF_SIZE], - queue_start: 0, - queue_end: 0, + buffer: Queue::new(), } } /// Initialize the UART. @@ -146,7 +143,8 @@ impl Uart { } } - while self.queue_start == self.queue_end + 1 { + // Sleep until there is space in the buffer. + while self.buffer.space_remaining() == 0 { unsafe { guard.sleep(addr_of!(*self).cast_mut().cast()); } @@ -157,10 +155,7 @@ impl Uart { let this: &mut Uart = unsafe { &mut *addr_of!(*self).cast_mut() }; // Add the byte onto the end of the queue. - this.buffer[this.queue_end] = b; - this.queue_end += 1; - this.queue_end %= this.buffer.len(); - + this.buffer.push_back(b).expect("space in the uart queue"); this.send_buffered_bytes(); } pub fn write_slice_buffered(&self, bytes: &[u8]) { @@ -175,14 +170,6 @@ impl Uart { let this: &mut Uart = unsafe { &mut *addr_of!(*self).cast_mut() }; loop { - // Ensure the indices are correct. - this.queue_start %= this.buffer.len(); - this.queue_end %= this.buffer.len(); - - if this.queue_start == this.queue_end { - // The buffer is empty, we're finished sending bytes. - return; - } if Register::LineStatus.read(this.base_address) & LSR_TX_IDLE == 0 { // The UART transmit holding register is full, // so we cannot give it another byte. @@ -191,9 +178,10 @@ impl Uart { } // Pop a byte from the front of the queue. - let b = this.buffer[this.queue_start]; - this.queue_start += 1; - this.queue_start %= this.buffer.len(); + let Some(b) = this.buffer.pop_front() else { + // The buffer is empty, we're finished sending bytes. + return; + }; // Maybe uartputc() is waiting for space in the buffer. unsafe { diff --git a/kernel/rustkernel/src/io/pipe.rs b/kernel/rustkernel/src/io/pipe.rs index 16d34ef..95adabe 100644 --- a/kernel/rustkernel/src/io/pipe.rs +++ b/kernel/rustkernel/src/io/pipe.rs @@ -36,6 +36,11 @@ impl Pipe { } } } +impl Default for Pipe { + fn default() -> Pipe { + Pipe::new() + } +} extern "C" { // pub fn pipealloc(a: *mut *mut File, b: *mut *mut File) -> i32; @@ -122,6 +127,7 @@ pub unsafe extern "C" fn pipewrite(pipe: *mut Pipe, addr: u64, n: i32) -> i32 { } #[no_mangle] +#[allow(clippy::while_immutable_condition)] pub unsafe extern "C" fn piperead(pipe: *mut Pipe, addr: u64, n: i32) -> i32 { let mut i = 0; let p = myproc(); diff --git a/kernel/rustkernel/src/lib.rs b/kernel/rustkernel/src/lib.rs index 574a2d0..26d4abc 100644 --- a/kernel/rustkernel/src/lib.rs +++ b/kernel/rustkernel/src/lib.rs @@ -13,6 +13,7 @@ pub mod fs; pub mod io; pub mod mem; pub mod proc; +pub mod queue; pub(crate) mod riscv; pub mod start; pub mod string; diff --git a/kernel/rustkernel/src/queue.rs b/kernel/rustkernel/src/queue.rs new file mode 100644 index 0000000..ddebb9d --- /dev/null +++ b/kernel/rustkernel/src/queue.rs @@ -0,0 +1,105 @@ +use core::iter::*; + +pub const QUEUE_SIZE: usize = 64; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum QueueError { + NoSpace, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Queue { + inner: [Option; QUEUE_SIZE], + /// The index of the first item in the queue. + queue_start: usize, + /// The length of the queue. + queue_len: usize, +} +impl Queue { + pub const fn new() -> Queue { + Queue { + inner: [None; QUEUE_SIZE], + queue_start: 0, + queue_len: 0, + } + } +} +impl Queue { + /// Accessor method for the length of the queue. + pub fn len(&self) -> usize { + self.queue_len + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + /// Returns how many items can currently be added to the queue. + pub fn space_remaining(&self) -> usize { + self.inner.len() - self.len() + } + /// Returns the index of the last item in the queue. + fn queue_end(&self) -> usize { + (self.queue_start + self.queue_len - 1) % self.inner.len() + } + + /// Removes an item from the front of the queue. + pub fn pop_front(&mut self) -> Option { + let item = self.inner[self.queue_start].take(); + if item.is_some() { + self.queue_start += 1; + self.queue_start %= self.inner.len(); + self.queue_len -= 1; + } + item + } + /// Adds an item to the front of the queue. + pub fn push_front(&mut self, value: T) -> Result<(), QueueError> { + if self.space_remaining() == 0 { + return Err(QueueError::NoSpace); + } + + if self.queue_start == 0 { + self.queue_start = self.inner.len() - 1; + } else { + self.queue_start -= 1; + } + self.inner[self.queue_start] = Some(value); + self.queue_len += 1; + Ok(()) + } + /// Removes an item from the end of the queue. + pub fn pop_back(&mut self) -> Option { + let item = self.inner[self.queue_start].take(); + if item.is_some() { + self.queue_len -= 1; + } + item + } + /// Adds an item to the end of the queue. + pub fn push_back(&mut self, value: T) -> Result<(), QueueError> { + if self.space_remaining() == 0 { + return Err(QueueError::NoSpace); + } + + self.queue_len += 1; + self.inner[self.queue_end()] = Some(value); + Ok(()) + } +} + +impl Iterator for Queue { + type Item = T; + + fn next(&mut self) -> Option { + self.pop_front() + } +} +impl DoubleEndedIterator for Queue { + fn next_back(&mut self) -> Option { + self.pop_back() + } +} +impl ExactSizeIterator for Queue { + fn len(&self) -> usize { + self.len() + } +}