From 66d5163ee75d7c4c722456f3b581bb2f85b65cd0 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 26 Nov 2019 11:32:36 +0000 Subject: [PATCH] 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 --- vmm/src/cpu.rs | 76 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index 0a2d1157c..538ae500c 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -346,7 +346,7 @@ pub struct CpuManager { vcpus_kill_signalled: Arc, vcpus_pause_signalled: Arc, reset_evt: EventFd, - threads: Vec>, + vcpu_states: Vec, selected_cpu: u8, } @@ -359,8 +359,12 @@ impl BusDevice for CpuManager { fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) { match offset { CPU_STATUS_OFFSET => { - // All CPUs are currently enabled - data[0] |= 1 << CPU_ENABLE_FLAG; + if self.selected_cpu < self.present_vcpus() { + let state = &self.vcpu_states[usize::from(self.selected_cpu)]; + if state.active() { + data[0] |= 1 << CPU_ENABLE_FLAG; + } + } } _ => { warn!( @@ -386,6 +390,39 @@ impl BusDevice for CpuManager { } } +struct VcpuState { + handle: Option>, +} + +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 { pub fn new( boot_vcpus: u8, @@ -459,7 +496,8 @@ impl CpuManager { let reset_evt = self.reset_evt.try_clone().unwrap(); let vcpu_kill_signalled = self.vcpus_kill_signalled.clone(); let vcpu_pause_signalled = self.vcpus_pause_signalled.clone(); - self.threads.push( + + let handle = Some( thread::Builder::new() .name(format!("vcpu{}", vcpu.id)) .spawn(move || { @@ -512,6 +550,8 @@ impl CpuManager { }) .map_err(Error::VcpuSpawn)?, ); + + self.vcpu_states.push(VcpuState { handle }); } // Unblock all CPU threads. @@ -526,16 +566,13 @@ impl CpuManager { // 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 // above. - for thread in self.threads.iter() { - let signum = validate_signal_num(VCPU_RTSIG_OFFSET, true).unwrap(); - unsafe { - libc::pthread_kill(thread.as_pthread_t(), signum); - } + for state in self.vcpu_states.iter() { + state.signal_thread(); } - // Wait for all the threads to finish - for thread in self.threads.drain(..) { - thread.join().map_err(|_| Error::ThreadCleanup)? + // Wait for all the threads to finish. This removes the state from the vector. + for mut state in self.vcpu_states.drain(..) { + state.join_thread()?; } Ok(()) @@ -548,11 +585,8 @@ impl CpuManager { // 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 // above. - for thread in self.threads.iter() { - let signum = validate_signal_num(VCPU_RTSIG_OFFSET, true).unwrap(); - unsafe { - libc::pthread_kill(thread.as_pthread_t(), signum); - } + for state in self.vcpu_states.iter() { + state.signal_thread(); } Ok(()) @@ -566,8 +600,8 @@ impl CpuManager { // 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 // and go back to vmx root. - for vcpu_thread in self.threads.iter() { - vcpu_thread.thread().unpark(); + for state in self.vcpu_states.iter() { + state.unpark_thread(); } Ok(()) } @@ -579,4 +613,8 @@ impl CpuManager { pub fn max_vcpus(&self) -> u8 { self.max_vcpus } + + fn present_vcpus(&self) -> u8 { + self.vcpu_states.len() as u8 + } }