mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
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:
parent
afbf824a48
commit
29b90a8aee
@ -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];
|
||||||
|
Loading…
Reference in New Issue
Block a user