vmm: Create and handle an exit event

An exit event is required to be created and handled for the purpose
of letting the guest kernel stop the VM.

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

View File

@ -213,6 +213,7 @@ struct DeviceManager {
// Serial port on 0x3f8 // Serial port on 0x3f8
serial: Arc<Mutex<devices::legacy::Serial>>, serial: Arc<Mutex<devices::legacy::Serial>>,
serial_evt: EventFd, serial_evt: EventFd,
exit_evt: EventFd,
} }
impl DeviceManager { impl DeviceManager {
@ -224,10 +225,13 @@ impl DeviceManager {
Box::new(stdout()), Box::new(stdout()),
))); )));
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFd)?;
Ok(DeviceManager { Ok(DeviceManager {
io_bus, io_bus,
serial, serial,
serial_evt, serial_evt,
exit_evt,
}) })
} }
@ -242,6 +246,7 @@ impl DeviceManager {
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
enum EpollDispatch { enum EpollDispatch {
Exit,
Stdin, Stdin,
} }
@ -255,8 +260,9 @@ impl EpollContext {
let raw_fd = epoll::create(true)?; let raw_fd = epoll::create(true)?;
// Initial capacity needs to be large enough to hold: // Initial capacity needs to be large enough to hold:
// * 1 exit event
// * 1 stdin event // * 1 stdin event
let mut dispatch_table = Vec::with_capacity(2); let mut dispatch_table = Vec::with_capacity(3);
dispatch_table.push(None); dispatch_table.push(None);
Ok(EpollContext { Ok(EpollContext {
@ -278,6 +284,22 @@ impl EpollContext {
Ok(()) Ok(())
} }
fn add_event<T>(&mut self, fd: &T, token: EpollDispatch) -> result::Result<(), io::Error>
where
T: AsRawFd,
{
let dispatch_index = self.dispatch_table.len() as u64;
epoll::ctl(
self.raw_fd,
epoll::ControlOptions::EPOLL_CTL_ADD,
fd.as_raw_fd(),
epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index),
)?;
self.dispatch_table.push(Some(token));
Ok(())
}
} }
impl AsRawFd for EpollContext { impl AsRawFd for EpollContext {
@ -353,6 +375,11 @@ impl<'a> Vm<'a> {
let mut 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)?;
// Let's add an exit event.
epoll
.add_event(&device_manager.exit_evt, EpollDispatch::Exit)
.map_err(Error::EpollError)?;
Ok(Vm { Ok(Vm {
fd, fd,
kernel, kernel,
@ -412,6 +439,15 @@ impl<'a> Vm<'a> {
if let Some(dispatch_type) = self.epoll.dispatch_table[dispatch_idx] { if let Some(dispatch_type) = self.epoll.dispatch_table[dispatch_idx] {
match dispatch_type { match dispatch_type {
EpollDispatch::Exit => {
// Consume the event.
self.devices.exit_evt.read().map_err(Error::EventFd)?;
// Safe because we're terminating the process anyway.
unsafe {
libc::_exit(0);
}
}
EpollDispatch::Stdin => { EpollDispatch::Stdin => {
let stdin = io::stdin(); let stdin = io::stdin();
let mut out = [0u8; 64]; let mut out = [0u8; 64];