From f59cad15a316aacce9e0bfabf2a4b7835195223a Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Wed, 4 Sep 2019 12:59:14 +0100 Subject: [PATCH] vmm: Cleanup signal_handler thread used for console SIGWINCH handling Do this by using the same mechanism as the vCPU threads by sending a signal to the thread. As this is the same mechanism reuse the same code and rename the "vcpus" member to "threads" to indicate this represents both the vCPU threads and also the signal handler thread. Signed-off-by: Rob Bradford --- vmm/src/vm.rs | 58 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 592ca28ca..abbcd1e65 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -46,6 +46,7 @@ use std::io::{self, sink, stdout}; use std::ops::Deref; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::os::unix::thread::JoinHandleExt; use std::ptr::null_mut; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Barrier, Mutex, RwLock}; @@ -1403,7 +1404,7 @@ pub struct Vm<'a> { fd: Arc, kernel: File, memory: Arc>, - vcpus: Vec>, + threads: Vec>, devices: DeviceManager, cpuid: CpuId, config: &'a VmConfig<'a>, @@ -1622,13 +1623,13 @@ impl<'a> Vm<'a> { .add_event(&device_manager.reset_evt, EpollDispatch::Reset) .map_err(Error::EpollError)?; - let vcpus = Vec::with_capacity(u8::from(&config.cpus) as usize); + let threads = Vec::with_capacity(u8::from(&config.cpus) as usize + 1); Ok(Vm { fd, kernel, memory: guest_memory, - vcpus, + threads, devices: device_manager, cpuid, config, @@ -1807,29 +1808,39 @@ impl<'a> Vm<'a> { // 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() { + // 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 { - use std::os::unix::thread::JoinHandleExt; - libc::pthread_kill(vcpu.as_pthread_t(), signum); + libc::pthread_kill(thread.as_pthread_t(), signum); } } - // Wait for all the vCPU threads to finish - for vcpu in self.vcpus.drain(..) { - vcpu.join().map_err(|_| Error::ThreadCleanup)? + // Wait for all the threads to finish + for thread in self.threads.drain(..) { + thread.join().map_err(|_| Error::ThreadCleanup)? } Ok(exit_behaviour) } - fn os_signal_handler(signals: Signals, console_input_clone: Arc) { + fn os_signal_handler( + signals: Signals, + console_input_clone: Arc, + quit_signum: i32, + ) { for signal in signals.forever() { - if signal == SIGWINCH { - let (col, row) = get_win_size(); - console_input_clone.update_console_size(col, row); + match signal { + SIGWINCH => { + let (col, row) = get_win_size(); + console_input_clone.update_console_size(col, row); + } + s if s == quit_signum => { + break; + } + _ => {} } } } @@ -1858,7 +1869,7 @@ impl<'a> Vm<'a> { let reset_evt = self.devices.reset_evt.try_clone().unwrap(); let vcpu_kill_signalled = self.vcpus_kill_signalled.clone(); - self.vcpus.push( + self.threads.push( thread::Builder::new() .name(format!("vcpu{}", vcpu.id)) .spawn(move || { @@ -1907,13 +1918,18 @@ impl<'a> Vm<'a> { if let Some(console_input) = &self.devices.console_input { let console_input_clone = console_input.clone(); - let signals = Signals::new(&[SIGWINCH]); + let quit_signum = validate_signal_num(VCPU_RTSIG_OFFSET, true).unwrap(); + let signals = Signals::new(&[SIGWINCH, quit_signum]); match signals { Ok(sig) => { - thread::Builder::new() - .name("signal_handler".to_string()) - .spawn(move || Vm::os_signal_handler(sig, console_input_clone)) - .map_err(Error::SignalHandlerSpawn)?; + self.threads.push( + thread::Builder::new() + .name("signal_handler".to_string()) + .spawn(move || { + Vm::os_signal_handler(sig, console_input_clone, quit_signum) + }) + .map_err(Error::SignalHandlerSpawn)?, + ); ; } Err(e) => error!("Signal not found {}", e),