(&mut self)
| 2601 | |
| 2602 | impl Pausable for CpuManager { |
| 2603 | fn pause(&mut self) -> std::result::Result<(), MigratableError> { |
| 2604 | // Tell the vCPUs to pause themselves next time they exit |
| 2605 | self.vcpus_pause_signalled.store(true, Ordering::SeqCst); |
| 2606 | |
| 2607 | self.signal_vcpus() |
| 2608 | .map_err(|e| MigratableError::Pause(anyhow!("Error signalling vCPUs: {e}")))?; |
| 2609 | |
| 2610 | // Notify all guests (including Hyper-V / Windows) that the clock was |
| 2611 | // paused. KVM_KVMCLOCK_CTRL updates internal KVM state that affects |
| 2612 | // both pvclock (Linux) and the Hyper-V TSC reference page, so it must |
| 2613 | // be called unconditionally. |
| 2614 | #[cfg(all(feature = "kvm", target_arch = "x86_64"))] |
| 2615 | for vcpu in self.vcpus.iter() { |
| 2616 | let vcpu = vcpu.lock().unwrap(); |
| 2617 | vcpu.vcpu.notify_guest_clock_paused().map_err(|e| { |
| 2618 | MigratableError::Pause(anyhow!("Could not notify guest it has been paused {e:?}")) |
| 2619 | })?; |
| 2620 | } |
| 2621 | |
| 2622 | // The vCPU thread will change its paused state before parking, wait here for each |
| 2623 | // activated vCPU change their state to ensure they have parked. |
| 2624 | for state in self.vcpu_states.lock().unwrap().iter() { |
| 2625 | if state.active() { |
| 2626 | // wait for vCPU to update state |
| 2627 | while !state.paused.load(Ordering::SeqCst) { |
| 2628 | // To avoid a priority inversion with the vCPU thread |
| 2629 | thread::sleep(std::time::Duration::from_millis(1)); |
| 2630 | } |
| 2631 | } |
| 2632 | } |
| 2633 | |
| 2634 | Ok(()) |
| 2635 | } |
| 2636 | |
| 2637 | fn resume(&mut self) -> std::result::Result<(), MigratableError> { |
| 2638 | // Ensure that vCPUs keep running after being unpark() in |
nothing calls this directly
no test coverage detected