mirror of
https://github.com/AmbiML/sparrow-kata-full.git
synced 2025-07-31 05:30:34 +00:00
Implements BufRead in kata_io
Reading one byte at a time in a loop causes excessive syscalls. For example, ZMODEM needs to do this when finding the end of each frame. This change copies parts of std::io needed to wrap a Read in a BufReader so that the read will be done eagerly. It enables buffered UART reads for the whole DebugConsole at the point where its single Read object is initialized. Change-Id: I19935ca02333bc74d9b581d384a1854968ac5329 GitOrigin-RevId: 1aa80e036561a6a18e79dbf28bcab240efe80cd1
This commit is contained in:
parent
d70003982c
commit
4faa2e4c82
@ -8,6 +8,7 @@ description = "Kata OS DebugConsole"
|
||||
[dependencies]
|
||||
panic-halt = "0.2.0"
|
||||
kata-allocator = { path = "../kata-allocator" }
|
||||
kata-io = { path = "../kata-io" }
|
||||
kata-logger = { path = "../kata-logger" }
|
||||
kata-panic = { path = "../kata-panic" }
|
||||
kata-shell = { path = "../kata-shell" }
|
||||
|
@ -15,6 +15,7 @@
|
||||
extern crate kata_panic;
|
||||
|
||||
use kata_allocator;
|
||||
use kata_io;
|
||||
use kata_logger::KataLogger;
|
||||
use kata_shell;
|
||||
use kata_uart_client;
|
||||
@ -45,6 +46,6 @@ pub extern "C" fn pre_init() {
|
||||
pub extern "C" fn run() -> ! {
|
||||
trace!("run");
|
||||
let mut tx = kata_uart_client::Tx::new();
|
||||
let mut rx = kata_uart_client::Rx::new();
|
||||
let mut rx = kata_io::BufReader::new(kata_uart_client::Rx::new());
|
||||
kata_shell::repl(&mut tx, &mut rx);
|
||||
}
|
||||
|
@ -3,3 +3,6 @@ name = "kata-io"
|
||||
version = "0.1.0"
|
||||
authors = ["Matt Harvey <mattharvey@google.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
memchr = { version = "2.4.1", default-features = false }
|
||||
|
@ -1,5 +1,9 @@
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use core::cmp;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -30,6 +34,38 @@ pub trait Read {
|
||||
}
|
||||
}
|
||||
|
||||
/// Partial mimic of std::io::BufRead.
|
||||
pub trait BufRead: Read {
|
||||
fn fill_buf(&mut self) -> Result<&[u8]>;
|
||||
|
||||
fn consume(&mut self, amt: usize);
|
||||
|
||||
fn read_until(&mut self, delim: u8, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
// Implementation adapted from std::io.
|
||||
let mut read = 0;
|
||||
loop {
|
||||
let (done, used) = {
|
||||
let available = self.fill_buf()?;
|
||||
match memchr::memchr(delim, available) {
|
||||
Some(i) => {
|
||||
buf.extend_from_slice(&available[..=i]);
|
||||
(true, i + 1)
|
||||
}
|
||||
None => {
|
||||
buf.extend_from_slice(available);
|
||||
(false, available.len())
|
||||
}
|
||||
}
|
||||
};
|
||||
self.consume(used);
|
||||
read += used;
|
||||
if done || used == 0 {
|
||||
return Ok(read);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Partial mimic of std::io::Write.
|
||||
pub trait Write {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize>;
|
||||
@ -103,3 +139,70 @@ where
|
||||
(**self).flush()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BufReader<R> {
|
||||
inner: R,
|
||||
buf: Box<[u8]>,
|
||||
pos: usize,
|
||||
cap: usize,
|
||||
}
|
||||
|
||||
impl<R: Read> BufReader<R> {
|
||||
pub fn new(inner: R) -> BufReader<R> {
|
||||
const BUFFER_SIZE : usize = 1024; // free to be changed
|
||||
BufReader {
|
||||
inner: inner,
|
||||
buf: Box::new([0u8; BUFFER_SIZE]),
|
||||
pos: 0,
|
||||
cap: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn discard_buffer(&mut self) {
|
||||
// Implementation copied from std::io.
|
||||
self.pos = 0;
|
||||
self.cap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> Read for BufReader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
// Implementation copied from std::io.
|
||||
|
||||
// If we don't have any buffered data and we're doing a massive read
|
||||
// (larger than our internal buffer), bypass our internal buffer
|
||||
// entirely.
|
||||
if self.pos == self.cap && buf.len() >= self.buf.len() {
|
||||
self.discard_buffer();
|
||||
return self.inner.read(buf);
|
||||
}
|
||||
let nread = {
|
||||
let mut rem = self.fill_buf()?;
|
||||
rem.read(buf)?
|
||||
};
|
||||
self.consume(nread);
|
||||
Ok(nread)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> BufRead for BufReader<R> {
|
||||
fn fill_buf(&mut self) -> Result<&[u8]> {
|
||||
// Implementation copied from std::io.
|
||||
|
||||
// If we've reached the end of our internal buffer then we need to fetch
|
||||
// some more data from the underlying reader.
|
||||
// Branch using `>=` instead of the more correct `==`
|
||||
// to tell the compiler that the pos..cap slice is always valid.
|
||||
if self.pos >= self.cap {
|
||||
debug_assert!(self.pos == self.cap);
|
||||
self.cap = self.inner.read(&mut self.buf)?;
|
||||
self.pos = 0;
|
||||
}
|
||||
Ok(&self.buf[self.pos..self.cap])
|
||||
}
|
||||
|
||||
fn consume(&mut self, amt: usize) {
|
||||
// Implementation copied from std::io.
|
||||
self.pos = cmp::min(self.pos + amt, self.cap);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user