mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: Shutdown vCPU threads
As part of the cleanup of the VM shutdown all the vCPU threads. This is achieved by toggling a shared atomic boolean variable which is checked in the vCPU loop. To trigger the vCPU code to look at this boolean it is necessary to send a signal to the vCPU which will interrupt the running KVM_RUN ioctl. Fixes: #229 Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
committed by
Samuel Ortiz
parent
40f9da524f
commit
bb2e7bb942
+31
-1
@@ -47,6 +47,7 @@ use std::ops::Deref;
|
|||||||
use std::os::unix::fs::OpenOptionsExt;
|
use std::os::unix::fs::OpenOptionsExt;
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, Barrier, Mutex, RwLock};
|
use std::sync::{Arc, Barrier, Mutex, RwLock};
|
||||||
use std::{fmt, result, str, thread};
|
use std::{fmt, result, str, thread};
|
||||||
use vfio::{VfioDevice, VfioPciDevice, VfioPciError};
|
use vfio::{VfioDevice, VfioPciDevice, VfioPciError};
|
||||||
@@ -59,7 +60,7 @@ use vm_memory::{
|
|||||||
use vm_virtio::transport::VirtioPciDevice;
|
use vm_virtio::transport::VirtioPciDevice;
|
||||||
use vm_virtio::{VirtioSharedMemory, VirtioSharedMemoryList};
|
use vm_virtio::{VirtioSharedMemory, VirtioSharedMemoryList};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
use vmm_sys_util::signal::register_signal_handler;
|
use vmm_sys_util::signal::{register_signal_handler, validate_signal_num};
|
||||||
use vmm_sys_util::terminal::Terminal;
|
use vmm_sys_util::terminal::Terminal;
|
||||||
|
|
||||||
const VCPU_RTSIG_OFFSET: i32 = 0;
|
const VCPU_RTSIG_OFFSET: i32 = 0;
|
||||||
@@ -225,6 +226,9 @@ pub enum Error {
|
|||||||
|
|
||||||
/// Cannot spawn a signal handler thread
|
/// Cannot spawn a signal handler thread
|
||||||
SignalHandlerSpawn(io::Error),
|
SignalHandlerSpawn(io::Error),
|
||||||
|
|
||||||
|
/// Failed to join on vCPU threads
|
||||||
|
ThreadCleanup,
|
||||||
}
|
}
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
@@ -1401,6 +1405,7 @@ pub struct Vm<'a> {
|
|||||||
epoll: EpollContext,
|
epoll: EpollContext,
|
||||||
on_tty: bool,
|
on_tty: bool,
|
||||||
creation_ts: std::time::Instant,
|
creation_ts: std::time::Instant,
|
||||||
|
vcpus_kill_signalled: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Vm<'a> {
|
impl<'a> Vm<'a> {
|
||||||
@@ -1625,6 +1630,7 @@ impl<'a> Vm<'a> {
|
|||||||
epoll,
|
epoll,
|
||||||
on_tty,
|
on_tty,
|
||||||
creation_ts,
|
creation_ts,
|
||||||
|
vcpus_kill_signalled: Arc::new(AtomicBool::new(false)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1793,6 +1799,24 @@ impl<'a> Vm<'a> {
|
|||||||
.map_err(Error::SetTerminalCanon)?;
|
.map_err(Error::SetTerminalCanon)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tell the vCPUs to stop themselves next time they go through the loop
|
||||||
|
self.vcpus_kill_signalled.store(true, Ordering::SeqCst);
|
||||||
|
|
||||||
|
// Signal to the vCPU threads. This will interrupt the KVM_RUN ioctl() allowing
|
||||||
|
// the loop to check the boolean set above.
|
||||||
|
for vcpu in self.vcpus.iter() {
|
||||||
|
let signum = validate_signal_num(VCPU_RTSIG_OFFSET, true).unwrap();
|
||||||
|
unsafe {
|
||||||
|
use std::os::unix::thread::JoinHandleExt;
|
||||||
|
libc::pthread_kill(vcpu.as_pthread_t(), signum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for all the vCPU threads to finish
|
||||||
|
for vcpu in self.vcpus.drain(..) {
|
||||||
|
vcpu.join().map_err(|_| Error::ThreadCleanup)?
|
||||||
|
}
|
||||||
|
|
||||||
Ok(exit_behaviour)
|
Ok(exit_behaviour)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1828,6 +1852,7 @@ impl<'a> Vm<'a> {
|
|||||||
let vcpu_thread_barrier = vcpu_thread_barrier.clone();
|
let vcpu_thread_barrier = vcpu_thread_barrier.clone();
|
||||||
|
|
||||||
let reset_evt = self.devices.reset_evt.try_clone().unwrap();
|
let reset_evt = self.devices.reset_evt.try_clone().unwrap();
|
||||||
|
let vcpu_kill_signalled = self.vcpus_kill_signalled.clone();
|
||||||
self.vcpus.push(
|
self.vcpus.push(
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name(format!("vcpu{}", vcpu.id))
|
.name(format!("vcpu{}", vcpu.id))
|
||||||
@@ -1861,6 +1886,11 @@ impl<'a> Vm<'a> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We've been told to terminate
|
||||||
|
if vcpu_kill_signalled.load(Ordering::SeqCst) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map_err(Error::VcpuSpawn)?,
|
.map_err(Error::VcpuSpawn)?,
|
||||||
|
|||||||
Reference in New Issue
Block a user