@@ -14,7 +14,7 @@ use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
1414use std:: thread;
1515
1616use super :: TimestampUs ;
17- use arch ;
17+ use super :: FC_EXIT_CODE_GENERIC_ERROR ;
1818#[ cfg( target_arch = "aarch64" ) ]
1919use arch:: aarch64:: gic:: GICDevice ;
2020#[ cfg( target_arch = "x86_64" ) ]
@@ -30,6 +30,7 @@ use kvm_bindings::{kvm_userspace_memory_region, KVM_API_VERSION};
3030use kvm_ioctls:: * ;
3131use logger:: { Metric , METRICS } ;
3232use seccomp:: { BpfProgram , SeccompFilter } ;
33+ use std:: sync:: Barrier ;
3334use utils:: eventfd:: EventFd ;
3435use utils:: signal:: { register_signal_handler, sigrtmin, Killable } ;
3536use utils:: sm:: StateMachine ;
@@ -1002,7 +1003,7 @@ impl Vcpu {
10021003 // Emulation was interrupted, check external events.
10031004 Ok ( VcpuEmulation :: Interrupted ) => break ,
10041005 // Emulation errors lead to vCPU exit.
1005- Err ( _) => return StateMachine :: next ( Self :: exited ) ,
1006+ Err ( _) => return self . exit ( FC_EXIT_CODE_GENERIC_ERROR ) ,
10061007 }
10071008 }
10081009
@@ -1032,7 +1033,7 @@ impl Vcpu {
10321033 // Unhandled exit of the other end.
10331034 Err ( TryRecvError :: Disconnected ) => {
10341035 // Move to 'exited' state.
1035- state = StateMachine :: next ( Self :: exited ) ;
1036+ state = self . exit ( FC_EXIT_CODE_GENERIC_ERROR ) ;
10361037 }
10371038 // All other events or lack thereof have no effect on current 'running' state.
10381039 Err ( TryRecvError :: Empty ) => ( ) ,
@@ -1058,18 +1059,33 @@ impl Vcpu {
10581059 // Unhandled exit of the other end.
10591060 Err ( _) => {
10601061 // Move to 'exited' state.
1061- StateMachine :: next ( Self :: exited )
1062+ self . exit ( FC_EXIT_CODE_GENERIC_ERROR )
10621063 }
10631064 }
10641065 }
10651066
1066- // This is the main loop of the `Exited` state.
1067- fn exited ( & mut self ) -> StateMachine < Self > {
1067+ // Transition to the exited state
1068+ fn exit ( & mut self , exit_code : u8 ) -> StateMachine < Self > {
1069+ self . response_sender
1070+ . send ( VcpuResponse :: Exited ( exit_code) )
1071+ . expect ( "failed to send Exited status" ) ;
1072+
10681073 if let Err ( e) = self . exit_evt . write ( 1 ) {
10691074 METRICS . vcpu . failures . inc ( ) ;
10701075 error ! ( "Failed signaling vcpu exit event: {}" , e) ;
10711076 }
1077+
10721078 // State machine reached its end.
1079+ StateMachine :: next ( Self :: exited)
1080+ }
1081+
1082+ // This is the main loop of the `Exited` state.
1083+ fn exited ( & mut self ) -> StateMachine < Self > {
1084+ // Wait indefinitely.
1085+ // The VMM thread will kill the entire process.
1086+ let barrier = Barrier :: new ( 2 ) ;
1087+ barrier. wait ( ) ;
1088+
10731089 StateMachine :: finish ( Self :: exited)
10741090 }
10751091}
@@ -1114,6 +1130,8 @@ pub enum VcpuResponse {
11141130 Paused ,
11151131 /// Vcpu is resumed.
11161132 Resumed ,
1133+ /// Vcpu is stopped.
1134+ Exited ( u8 ) ,
11171135}
11181136
11191137/// Wrapper over Vcpu that hides the underlying interactions with the Vcpu thread.
0 commit comments