vmm: cpu: Encapsulate vCPU state into its own struct

Currently this just holds the thread handle but will be enlarged to
encompass details such as whether the vCPU is currently being inserted
or ejected.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford
2019-11-26 11:32:36 +00:00
parent ea19bb026f
commit 66d5163ee7
+57 -19
View File
@@ -346,7 +346,7 @@ pub struct CpuManager {
vcpus_kill_signalled: Arc<AtomicBool>, vcpus_kill_signalled: Arc<AtomicBool>,
vcpus_pause_signalled: Arc<AtomicBool>, vcpus_pause_signalled: Arc<AtomicBool>,
reset_evt: EventFd, reset_evt: EventFd,
threads: Vec<thread::JoinHandle<()>>, vcpu_states: Vec<VcpuState>,
selected_cpu: u8, selected_cpu: u8,
} }
@@ -359,8 +359,12 @@ impl BusDevice for CpuManager {
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) { fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
match offset { match offset {
CPU_STATUS_OFFSET => { CPU_STATUS_OFFSET => {
// All CPUs are currently enabled if self.selected_cpu < self.present_vcpus() {
data[0] |= 1 << CPU_ENABLE_FLAG; let state = &self.vcpu_states[usize::from(self.selected_cpu)];
if state.active() {
data[0] |= 1 << CPU_ENABLE_FLAG;
}
}
} }
_ => { _ => {
warn!( warn!(
@@ -386,6 +390,39 @@ impl BusDevice for CpuManager {
} }
} }
struct VcpuState {
handle: Option<thread::JoinHandle<()>>,
}
impl VcpuState {
fn active(&self) -> bool {
self.handle.is_some()
}
fn signal_thread(&self) {
if let Some(handle) = self.handle.as_ref() {
let signum = validate_signal_num(VCPU_RTSIG_OFFSET, true).unwrap();
unsafe {
libc::pthread_kill(handle.as_pthread_t(), signum);
}
}
}
fn join_thread(&mut self) -> Result<()> {
if let Some(handle) = self.handle.take() {
handle.join().map_err(|_| Error::ThreadCleanup)?
}
Ok(())
}
fn unpark_thread(&self) {
if let Some(handle) = self.handle.as_ref() {
handle.thread().unpark()
}
}
}
impl CpuManager { impl CpuManager {
pub fn new( pub fn new(
boot_vcpus: u8, boot_vcpus: u8,
@@ -459,7 +496,8 @@ impl CpuManager {
let reset_evt = self.reset_evt.try_clone().unwrap(); let reset_evt = self.reset_evt.try_clone().unwrap();
let vcpu_kill_signalled = self.vcpus_kill_signalled.clone(); let vcpu_kill_signalled = self.vcpus_kill_signalled.clone();
let vcpu_pause_signalled = self.vcpus_pause_signalled.clone(); let vcpu_pause_signalled = self.vcpus_pause_signalled.clone();
self.threads.push(
let handle = Some(
thread::Builder::new() thread::Builder::new()
.name(format!("vcpu{}", vcpu.id)) .name(format!("vcpu{}", vcpu.id))
.spawn(move || { .spawn(move || {
@@ -512,6 +550,8 @@ impl CpuManager {
}) })
.map_err(Error::VcpuSpawn)?, .map_err(Error::VcpuSpawn)?,
); );
self.vcpu_states.push(VcpuState { handle });
} }
// Unblock all CPU threads. // Unblock all CPU threads.
@@ -526,16 +566,13 @@ impl CpuManager {
// Signal to the spawned threads (vCPUs and console signal handler). For the vCPU threads // Signal to the spawned threads (vCPUs and console signal handler). For the vCPU threads
// this will interrupt the KVM_RUN ioctl() allowing the loop to check the boolean set // this will interrupt the KVM_RUN ioctl() allowing the loop to check the boolean set
// above. // above.
for thread in self.threads.iter() { for state in self.vcpu_states.iter() {
let signum = validate_signal_num(VCPU_RTSIG_OFFSET, true).unwrap(); state.signal_thread();
unsafe {
libc::pthread_kill(thread.as_pthread_t(), signum);
}
} }
// Wait for all the threads to finish // Wait for all the threads to finish. This removes the state from the vector.
for thread in self.threads.drain(..) { for mut state in self.vcpu_states.drain(..) {
thread.join().map_err(|_| Error::ThreadCleanup)? state.join_thread()?;
} }
Ok(()) Ok(())
@@ -548,11 +585,8 @@ impl CpuManager {
// Signal to the spawned threads (vCPUs and console signal handler). For the vCPU threads // Signal to the spawned threads (vCPUs and console signal handler). For the vCPU threads
// this will interrupt the KVM_RUN ioctl() allowing the loop to check the boolean set // this will interrupt the KVM_RUN ioctl() allowing the loop to check the boolean set
// above. // above.
for thread in self.threads.iter() { for state in self.vcpu_states.iter() {
let signum = validate_signal_num(VCPU_RTSIG_OFFSET, true).unwrap(); state.signal_thread();
unsafe {
libc::pthread_kill(thread.as_pthread_t(), signum);
}
} }
Ok(()) Ok(())
@@ -566,8 +600,8 @@ impl CpuManager {
// Once unparked, the next thing they will do is checking for the pause // Once unparked, the next thing they will do is checking for the pause
// boolean. Since it'll be set to false, they will exit their pause loop // boolean. Since it'll be set to false, they will exit their pause loop
// and go back to vmx root. // and go back to vmx root.
for vcpu_thread in self.threads.iter() { for state in self.vcpu_states.iter() {
vcpu_thread.thread().unpark(); state.unpark_thread();
} }
Ok(()) Ok(())
} }
@@ -579,4 +613,8 @@ impl CpuManager {
pub fn max_vcpus(&self) -> u8 { pub fn max_vcpus(&self) -> u8 {
self.max_vcpus self.max_vcpus
} }
fn present_vcpus(&self) -> u8 {
self.vcpu_states.len() as u8
}
} }