vmm: Handle stdin from a generic epoll loop

Instead of handling stdin in its own separate loop, we use a generic
one that can be reused for other events handling.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2019-04-15 10:14:31 -07:00 committed by Samuel Ortiz
parent a7bdf5ee48
commit afbf824a48

View File

@ -240,24 +240,42 @@ impl DeviceManager {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq)]
enum EpollDispatch {
Stdin,
}
pub struct EpollContext { pub struct EpollContext {
raw_fd: RawFd, raw_fd: RawFd,
dispatch_table: Vec<Option<EpollDispatch>>,
} }
impl EpollContext { impl EpollContext {
pub fn new() -> result::Result<EpollContext, io::Error> { pub fn new() -> result::Result<EpollContext, io::Error> {
let raw_fd = epoll::create(true)?; let raw_fd = epoll::create(true)?;
Ok(EpollContext { raw_fd })
// Initial capacity needs to be large enough to hold:
// * 1 stdin event
let mut dispatch_table = Vec::with_capacity(2);
dispatch_table.push(None);
Ok(EpollContext {
raw_fd,
dispatch_table,
})
} }
pub fn add_stdin(&self) -> result::Result<(), io::Error> { pub fn add_stdin(&mut self) -> result::Result<(), io::Error> {
let dispatch_index = self.dispatch_table.len() as u64;
epoll::ctl( epoll::ctl(
self.raw_fd, self.raw_fd,
epoll::ControlOptions::EPOLL_CTL_ADD, epoll::ControlOptions::EPOLL_CTL_ADD,
libc::STDIN_FILENO, libc::STDIN_FILENO,
epoll::Event::new(epoll::Events::EPOLLIN, libc::STDIN_FILENO as u64), epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index),
)?; )?;
self.dispatch_table.push(Some(EpollDispatch::Stdin));
Ok(()) Ok(())
} }
} }
@ -332,7 +350,7 @@ impl<'a> Vm<'a> {
.map_err(Error::Irq)?; .map_err(Error::Irq)?;
// Let's add our STDIN fd. // Let's add our STDIN fd.
let epoll = EpollContext::new().map_err(Error::EpollError)?; let mut epoll = EpollContext::new().map_err(Error::EpollError)?;
epoll.add_stdin().map_err(Error::EpollError)?; epoll.add_stdin().map_err(Error::EpollError)?;
Ok(Vm { Ok(Vm {
@ -378,9 +396,10 @@ impl<'a> Vm<'a> {
Ok(entry_addr.kernel_load) Ok(entry_addr.kernel_load)
} }
pub fn stdin_loop(&mut self) -> Result<()> { pub fn control_loop(&mut self) -> Result<()> {
// Let's start the STDIN polling thread. // Let's start the STDIN polling thread.
const EPOLL_EVENTS_LEN: usize = 10; const EPOLL_EVENTS_LEN: usize = 100;
let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN]; let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
let epoll_fd = self.epoll.as_raw_fd(); let epoll_fd = self.epoll.as_raw_fd();
@ -389,20 +408,24 @@ impl<'a> Vm<'a> {
epoll::wait(epoll_fd, -1, &mut events[..]).map_err(Error::EpollError)?; epoll::wait(epoll_fd, -1, &mut events[..]).map_err(Error::EpollError)?;
for event in events.iter().take(num_events) { for event in events.iter().take(num_events) {
let event_data = event.data as RawFd; let dispatch_idx = event.data as usize;
if let libc::STDIN_FILENO = event_data { if let Some(dispatch_type) = self.epoll.dispatch_table[dispatch_idx] {
let stdin = io::stdin(); match dispatch_type {
let mut out = [0u8; 64]; EpollDispatch::Stdin => {
let stdin_lock = stdin.lock(); let stdin = io::stdin();
let count = stdin_lock.read_raw(&mut out).map_err(Error::Serial)?; let mut out = [0u8; 64];
let stdin_lock = stdin.lock();
let count = stdin_lock.read_raw(&mut out).map_err(Error::Serial)?;
self.devices self.devices
.serial .serial
.lock() .lock()
.expect("Failed to process stdin event due to poisoned lock") .expect("Failed to process stdin event due to poisoned lock")
.queue_input_bytes(&out[..count]) .queue_input_bytes(&out[..count])
.map_err(Error::Serial)?; .map_err(Error::Serial)?;
}
}
} }
} }
} }
@ -513,7 +536,7 @@ impl<'a> Vm<'a> {
// Unblock all CPU threads. // Unblock all CPU threads.
vcpu_thread_barrier.wait(); vcpu_thread_barrier.wait();
self.stdin_loop()?; self.control_loop()?;
for vcpu_barrier in vcpus { for vcpu_barrier in vcpus {
vcpu_barrier.join().unwrap(); vcpu_barrier.join().unwrap();