@@ -651,39 +651,8 @@ impl Vmm {
651651
652652 /// Signals Vmm to stop and exit.
653653 pub fn stop ( & mut self , exit_code : FcExitCode ) {
654- // To avoid cycles, all teardown paths take the following route:
655- // +------------------------+----------------------------+------------------------+
656- // | Vmm | Action | Vcpu |
657- // +------------------------+----------------------------+------------------------+
658- // 1 | | | vcpu.exit(exit_code) |
659- // 2 | | | vcpu.exit_evt.write(1) |
660- // 3 | | <--- EventFd::exit_evt --- | |
661- // 4 | vmm.stop() | | |
662- // 5 | | --- VcpuEvent::Finish ---> | |
663- // 6 | | | StateMachine::finish() |
664- // 7 | VcpuHandle::join() | | |
665- // 8 | vmm.shutdown_exit_code becomes Some(exit_code) breaking the main event loop |
666- // +------------------------+----------------------------+------------------------+
667- // Vcpu initiated teardown starts from `fn Vcpu::exit()` (step 1).
668- // Vmm initiated teardown starts from `pub fn Vmm::stop()` (step 4).
669- // Once `vmm.shutdown_exit_code` becomes `Some(exit_code)`, it is the upper layer's
670- // responsibility to break main event loop and propagate the exit code value.
671654 info ! ( "Vmm is stopping." ) ;
672655
673- // We send a "Finish" event. If a VCPU has already exited, this is the only
674- // message it will accept... but running and paused will take it as well.
675- // It breaks out of the state machine loop so that the thread can be joined.
676- for ( idx, handle) in self . vcpus_handles . iter_mut ( ) . enumerate ( ) {
677- if let Err ( err) = handle. send_event ( VcpuEvent :: Finish ) {
678- error ! ( "Failed to send VcpuEvent::Finish to vCPU {}: {}" , idx, err) ;
679- }
680- }
681- // The actual thread::join() that runs to release the thread's resource is done in
682- // the VcpuHandle's Drop trait. We can trigger that to happen now by clearing the
683- // list of handles. Do it here instead of Vmm::Drop to avoid dependency cycles.
684- // (Vmm's Drop will also check if this list is empty).
685- self . vcpus_handles . clear ( ) ;
686-
687656 // Break the main event loop, propagating the Vmm exit-code.
688657 self . shutdown_exit_code = Some ( exit_code) ;
689658 }
@@ -722,26 +691,17 @@ fn construct_kvm_mpidrs(vcpu_states: &[VcpuState]) -> Vec<u64> {
722691
723692impl Drop for Vmm {
724693 fn drop ( & mut self ) {
725- // There are two cases when `drop()` is called:
726- // 1) before the Vmm has been mutexed and subscribed to the event manager, or
727- // 2) after the Vmm has been registered as a subscriber to the event manager.
728- //
729- // The first scenario is bound to happen if an error is raised during
730- // Vmm creation (for example, during snapshot load), before the Vmm has
731- // been subscribed to the event manager. If that happens, the `drop()`
732- // function is called right before propagating the error. In order to
733- // be able to gracefully exit Firecracker with the correct fault
734- // message, we need to prepare the Vmm contents for the tear down
735- // (join the vcpu threads). Explicitly calling `stop()` allows the
736- // Vmm to be successfully dropped and firecracker to propagate the
737- // error.
738- //
739- // In the second case, before dropping the Vmm object, the event
740- // manager calls `stop()`, which sends a `Finish` event to the vcpus
741- // and joins the vcpu threads. The Vmm is dropped after everything is
742- // ready to be teared down. The line below is a no-op, because the Vmm
743- // has already been stopped by the event manager at this point.
744- self . stop ( self . shutdown_exit_code . unwrap_or ( FcExitCode :: Ok ) ) ;
694+ info ! ( "Killing vCPU threads" ) ;
695+
696+ // Send a "Finish" event to the vCPU threads so that they terminate.
697+ for ( idx, handle) in self . vcpus_handles . iter_mut ( ) . enumerate ( ) {
698+ if let Err ( err) = handle. send_event ( VcpuEvent :: Finish ) {
699+ error ! ( "Failed to send VcpuEvent::Finish to vCPU {}: {}" , idx, err) ;
700+ }
701+ }
702+
703+ // Join the vCPU threads by running VcpuHandle::drop().
704+ self . vcpus_handles . clear ( ) ;
745705
746706 if let Err ( err) = std:: io:: stdin ( ) . lock ( ) . set_canon_mode ( ) {
747707 warn ! ( "Cannot set canonical mode for the terminal. {:?}" , err) ;
0 commit comments