2021-08-31 15:03:44 +00:00
|
|
|
// Copyright © 2021 Intel Corporation
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
//
|
|
|
|
|
2021-09-24 05:32:41 +00:00
|
|
|
use crate::serial_manager::EpollDispatch;
|
|
|
|
|
2021-08-31 15:03:44 +00:00
|
|
|
use std::io::Write;
|
2021-09-24 05:32:41 +00:00
|
|
|
use std::os::unix::io::RawFd;
|
2021-08-31 15:03:44 +00:00
|
|
|
|
|
|
|
// Circular buffer implementation for serial output.
|
|
|
|
// Read from head; push to tail
|
|
|
|
pub(crate) struct SerialBuffer {
|
|
|
|
buffer: Vec<u8>,
|
|
|
|
head: usize,
|
|
|
|
tail: usize,
|
|
|
|
out: Box<dyn Write + Send>,
|
2021-09-24 05:32:41 +00:00
|
|
|
buffering: bool,
|
|
|
|
out_fd: Option<RawFd>,
|
|
|
|
epoll_fd: Option<RawFd>,
|
2021-08-31 15:03:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const MAX_BUFFER_SIZE: usize = 16 << 10;
|
|
|
|
|
|
|
|
impl SerialBuffer {
|
|
|
|
pub(crate) fn new(out: Box<dyn Write + Send>) -> Self {
|
|
|
|
Self {
|
|
|
|
buffer: vec![],
|
|
|
|
head: 0,
|
|
|
|
tail: 0,
|
|
|
|
out,
|
2021-09-24 05:32:41 +00:00
|
|
|
buffering: false,
|
|
|
|
out_fd: None,
|
|
|
|
epoll_fd: None,
|
2021-08-31 15:03:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-24 05:32:41 +00:00
|
|
|
pub(crate) fn add_out_fd(&mut self, out_fd: RawFd) {
|
|
|
|
self.out_fd = Some(out_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn add_epoll_fd(&mut self, epoll_fd: RawFd) {
|
|
|
|
self.epoll_fd = Some(epoll_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn flush_buffer(&mut self) -> Result<(), std::io::Error> {
|
2021-08-31 15:03:44 +00:00
|
|
|
if self.tail <= self.head {
|
|
|
|
// The buffer to be written is in two parts
|
|
|
|
let buf = &self.buffer[self.head..];
|
|
|
|
match self.out.write(buf) {
|
|
|
|
Ok(bytes_written) => {
|
|
|
|
if bytes_written == buf.len() {
|
|
|
|
self.head = 0;
|
|
|
|
// Can now proceed to write the other part of the buffer
|
|
|
|
} else {
|
|
|
|
self.head += bytes_written;
|
|
|
|
self.out.flush()?;
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
if !matches!(e.kind(), std::io::ErrorKind::WouldBlock) {
|
|
|
|
return Err(e);
|
|
|
|
}
|
2021-09-24 05:32:41 +00:00
|
|
|
self.add_out_poll()?;
|
2021-08-31 15:03:44 +00:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let buf = &self.buffer[self.head..self.tail];
|
|
|
|
match self.out.write(buf) {
|
|
|
|
Ok(bytes_written) => {
|
|
|
|
if bytes_written == buf.len() {
|
|
|
|
self.buffer.clear();
|
|
|
|
self.buffer.shrink_to_fit();
|
|
|
|
self.head = 0;
|
|
|
|
self.tail = 0;
|
2021-09-24 05:32:41 +00:00
|
|
|
self.remove_out_poll()?;
|
2021-08-31 15:03:44 +00:00
|
|
|
} else {
|
|
|
|
self.head += bytes_written;
|
|
|
|
}
|
|
|
|
self.out.flush()?;
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
if !matches!(e.kind(), std::io::ErrorKind::WouldBlock) {
|
|
|
|
return Err(e);
|
|
|
|
}
|
2021-09-24 05:32:41 +00:00
|
|
|
self.add_out_poll()?;
|
2021-08-31 15:03:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2021-09-24 05:32:41 +00:00
|
|
|
|
|
|
|
fn add_out_poll(&mut self) -> Result<(), std::io::Error> {
|
|
|
|
if self.out_fd.is_some() && self.epoll_fd.is_some() && !self.buffering {
|
|
|
|
self.buffering = true;
|
|
|
|
let out_fd = self.out_fd.as_ref().unwrap();
|
|
|
|
let epoll_fd = self.epoll_fd.as_ref().unwrap();
|
|
|
|
epoll::ctl(
|
|
|
|
*epoll_fd,
|
|
|
|
epoll::ControlOptions::EPOLL_CTL_MOD,
|
|
|
|
*out_fd,
|
|
|
|
epoll::Event::new(
|
|
|
|
epoll::Events::EPOLLIN | epoll::Events::EPOLLOUT,
|
|
|
|
EpollDispatch::File as u64,
|
|
|
|
),
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn remove_out_poll(&mut self) -> Result<(), std::io::Error> {
|
|
|
|
if self.out_fd.is_some() && self.epoll_fd.is_some() && self.buffering {
|
|
|
|
self.buffering = false;
|
|
|
|
let out_fd = self.out_fd.as_ref().unwrap();
|
|
|
|
let epoll_fd = self.epoll_fd.as_ref().unwrap();
|
|
|
|
epoll::ctl(
|
|
|
|
*epoll_fd,
|
|
|
|
epoll::ControlOptions::EPOLL_CTL_MOD,
|
|
|
|
*out_fd,
|
|
|
|
epoll::Event::new(epoll::Events::EPOLLIN, EpollDispatch::File as u64),
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2021-08-31 15:03:44 +00:00
|
|
|
}
|
|
|
|
impl Write for SerialBuffer {
|
|
|
|
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
|
|
|
|
// The serial output only writes one byte at a time
|
|
|
|
for v in buf {
|
|
|
|
if self.buffer.is_empty() {
|
|
|
|
// This case exists to avoid allocating the buffer if it's not needed
|
|
|
|
if let Err(e) = self.out.write(&[*v]) {
|
|
|
|
if !matches!(e.kind(), std::io::ErrorKind::WouldBlock) {
|
|
|
|
return Err(e);
|
|
|
|
}
|
2021-09-24 05:32:41 +00:00
|
|
|
self.add_out_poll()?;
|
2021-08-31 15:03:44 +00:00
|
|
|
self.buffer.push(*v);
|
|
|
|
self.tail += 1;
|
|
|
|
} else {
|
|
|
|
self.out.flush()?;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Buffer is completely full, lose the oldest byte by moving head forward
|
|
|
|
if self.head == self.tail {
|
|
|
|
self.head = self.tail + 1;
|
|
|
|
if self.head == MAX_BUFFER_SIZE {
|
|
|
|
self.head = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.buffer.len() < MAX_BUFFER_SIZE {
|
|
|
|
self.buffer.push(*v);
|
|
|
|
} else {
|
|
|
|
self.buffer[self.tail] = *v;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.tail += 1;
|
|
|
|
if self.tail == MAX_BUFFER_SIZE {
|
|
|
|
self.tail = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.flush_buffer()?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(buf.len())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn flush(&mut self) -> Result<(), std::io::Error> {
|
2021-09-24 05:32:41 +00:00
|
|
|
self.flush_buffer()
|
2021-08-31 15:03:44 +00:00
|
|
|
}
|
|
|
|
}
|