Implement basic queue type for convenience
This commit is contained in:
parent
6a41a4e8b8
commit
b3be1f8d47
@ -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<u8>,
|
||||
}
|
||||
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 {
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
105
kernel/rustkernel/src/queue.rs
Normal file
105
kernel/rustkernel/src/queue.rs
Normal file
@ -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<T> {
|
||||
inner: [Option<T>; QUEUE_SIZE],
|
||||
/// The index of the first item in the queue.
|
||||
queue_start: usize,
|
||||
/// The length of the queue.
|
||||
queue_len: usize,
|
||||
}
|
||||
impl<T: Copy> Queue<T> {
|
||||
pub const fn new() -> Queue<T> {
|
||||
Queue {
|
||||
inner: [None; QUEUE_SIZE],
|
||||
queue_start: 0,
|
||||
queue_len: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> Queue<T> {
|
||||
/// 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<T> {
|
||||
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<T> {
|
||||
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<T> Iterator for Queue<T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.pop_front()
|
||||
}
|
||||
}
|
||||
impl<T> DoubleEndedIterator for Queue<T> {
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.pop_back()
|
||||
}
|
||||
}
|
||||
impl<T> ExactSizeIterator for Queue<T> {
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user