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.
|
//! Low-level driver routines for 16550a UART.
|
||||||
#![allow(non_upper_case_globals)]
|
#![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;
|
use core::ptr::addr_of;
|
||||||
|
|
||||||
// The UART control registers.
|
// The UART control registers.
|
||||||
@ -22,8 +25,6 @@ const LSR_RX_READY: u8 = 1 << 0;
|
|||||||
/// THR can accept another character to send
|
/// THR can accept another character to send
|
||||||
const LSR_TX_IDLE: u8 = 1 << 5;
|
const LSR_TX_IDLE: u8 = 1 << 5;
|
||||||
|
|
||||||
const UART_TX_BUF_SIZE: usize = 32;
|
|
||||||
|
|
||||||
pub static UART0: Uart = Uart::new(crate::riscv::memlayout::UART0);
|
pub static UART0: Uart = Uart::new(crate::riscv::memlayout::UART0);
|
||||||
|
|
||||||
enum Register {
|
enum Register {
|
||||||
@ -61,18 +62,14 @@ impl Register {
|
|||||||
pub struct Uart {
|
pub struct Uart {
|
||||||
pub lock: Spinlock,
|
pub lock: Spinlock,
|
||||||
pub base_address: usize,
|
pub base_address: usize,
|
||||||
pub buffer: [u8; UART_TX_BUF_SIZE],
|
pub buffer: Queue<u8>,
|
||||||
pub queue_start: usize,
|
|
||||||
pub queue_end: usize,
|
|
||||||
}
|
}
|
||||||
impl Uart {
|
impl Uart {
|
||||||
pub const fn new(base_address: usize) -> Uart {
|
pub const fn new(base_address: usize) -> Uart {
|
||||||
Uart {
|
Uart {
|
||||||
lock: Spinlock::new(),
|
lock: Spinlock::new(),
|
||||||
base_address,
|
base_address,
|
||||||
buffer: [0u8; UART_TX_BUF_SIZE],
|
buffer: Queue::new(),
|
||||||
queue_start: 0,
|
|
||||||
queue_end: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Initialize the UART.
|
/// 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 {
|
unsafe {
|
||||||
guard.sleep(addr_of!(*self).cast_mut().cast());
|
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() };
|
let this: &mut Uart = unsafe { &mut *addr_of!(*self).cast_mut() };
|
||||||
|
|
||||||
// Add the byte onto the end of the queue.
|
// Add the byte onto the end of the queue.
|
||||||
this.buffer[this.queue_end] = b;
|
this.buffer.push_back(b).expect("space in the uart queue");
|
||||||
this.queue_end += 1;
|
|
||||||
this.queue_end %= this.buffer.len();
|
|
||||||
|
|
||||||
this.send_buffered_bytes();
|
this.send_buffered_bytes();
|
||||||
}
|
}
|
||||||
pub fn write_slice_buffered(&self, bytes: &[u8]) {
|
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() };
|
let this: &mut Uart = unsafe { &mut *addr_of!(*self).cast_mut() };
|
||||||
|
|
||||||
loop {
|
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 {
|
if Register::LineStatus.read(this.base_address) & LSR_TX_IDLE == 0 {
|
||||||
// The UART transmit holding register is full,
|
// The UART transmit holding register is full,
|
||||||
// so we cannot give it another byte.
|
// so we cannot give it another byte.
|
||||||
@ -191,9 +178,10 @@ impl Uart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pop a byte from the front of the queue.
|
// Pop a byte from the front of the queue.
|
||||||
let b = this.buffer[this.queue_start];
|
let Some(b) = this.buffer.pop_front() else {
|
||||||
this.queue_start += 1;
|
// The buffer is empty, we're finished sending bytes.
|
||||||
this.queue_start %= this.buffer.len();
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
// Maybe uartputc() is waiting for space in the buffer.
|
// Maybe uartputc() is waiting for space in the buffer.
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -36,6 +36,11 @@ impl Pipe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Default for Pipe {
|
||||||
|
fn default() -> Pipe {
|
||||||
|
Pipe::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// pub fn pipealloc(a: *mut *mut File, b: *mut *mut File) -> i32;
|
// 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]
|
#[no_mangle]
|
||||||
|
#[allow(clippy::while_immutable_condition)]
|
||||||
pub unsafe extern "C" fn piperead(pipe: *mut Pipe, addr: u64, n: i32) -> i32 {
|
pub unsafe extern "C" fn piperead(pipe: *mut Pipe, addr: u64, n: i32) -> i32 {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let p = myproc();
|
let p = myproc();
|
||||||
|
@ -13,6 +13,7 @@ pub mod fs;
|
|||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
pub mod proc;
|
pub mod proc;
|
||||||
|
pub mod queue;
|
||||||
pub(crate) mod riscv;
|
pub(crate) mod riscv;
|
||||||
pub mod start;
|
pub mod start;
|
||||||
pub mod string;
|
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