@@ -397,42 +397,53 @@ impl HypervLinuxDriver {
397397
398398        Self :: setup_initial_sregs ( & mut  vcpu_fd,  pml4_ptr. absolute ( ) ?) ?; 
399399
400-         Ok ( Self  { 
400+         let  interrupt_handle = Arc :: new ( LinuxInterruptHandle  { 
401+             running :  AtomicU64 :: new ( 0 ) , 
402+             cancel_requested :  AtomicBool :: new ( false ) , 
403+             #[ cfg( gdb) ]  
404+             debug_interrupt :  AtomicBool :: new ( false ) , 
405+             #[ cfg( all(  
406+                 target_arch = "x86_64" ,  
407+                 target_vendor = "unknown" ,  
408+                 target_os = "linux" ,  
409+                 target_env = "musl"  
410+             ) ) ]  
411+             tid :  AtomicU64 :: new ( unsafe  {  libc:: pthread_self ( )  as  u64  } ) , 
412+             #[ cfg( not( all(  
413+                 target_arch = "x86_64" ,  
414+                 target_vendor = "unknown" ,  
415+                 target_os = "linux" ,  
416+                 target_env = "musl"  
417+             ) ) ) ]  
418+             tid :  AtomicU64 :: new ( unsafe  {  libc:: pthread_self ( )  } ) , 
419+             retry_delay :  config. get_interrupt_retry_delay ( ) , 
420+             sig_rt_min_offset :  config. get_interrupt_vcpu_sigrtmin_offset ( ) , 
421+             dropped :  AtomicBool :: new ( false ) , 
422+         } ) ; 
423+ 
424+         #[ allow( unused_mut) ]  
425+         let  mut  hv = Self  { 
401426            _mshv :  mshv, 
402427            vm_fd, 
403428            vcpu_fd, 
404429            mem_regions, 
405430            entrypoint :  entrypoint_ptr. absolute ( ) ?, 
406431            orig_rsp :  rsp_ptr, 
407-             interrupt_handle :  Arc :: new ( LinuxInterruptHandle  { 
408-                 running :  AtomicU64 :: new ( 0 ) , 
409-                 cancel_requested :  AtomicBool :: new ( false ) , 
410-                 #[ cfg( all(  
411-                     target_arch = "x86_64" ,  
412-                     target_vendor = "unknown" ,  
413-                     target_os = "linux" ,  
414-                     target_env = "musl"  
415-                 ) ) ]  
416-                 tid :  AtomicU64 :: new ( unsafe  {  libc:: pthread_self ( )  as  u64  } ) , 
417-                 #[ cfg( not( all(  
418-                     target_arch = "x86_64" ,  
419-                     target_vendor = "unknown" ,  
420-                     target_os = "linux" ,  
421-                     target_env = "musl"  
422-                 ) ) ) ]  
423-                 tid :  AtomicU64 :: new ( unsafe  {  libc:: pthread_self ( )  } ) , 
424-                 retry_delay :  config. get_interrupt_retry_delay ( ) , 
425-                 sig_rt_min_offset :  config. get_interrupt_vcpu_sigrtmin_offset ( ) , 
426-                 dropped :  AtomicBool :: new ( false ) , 
427-             } ) , 
428- 
432+             interrupt_handle :  interrupt_handle. clone ( ) , 
429433            #[ cfg( gdb) ]  
430434            debug, 
431435            #[ cfg( gdb) ]  
432436            gdb_conn, 
433437            #[ cfg( crashdump) ]  
434438            rt_cfg, 
435-         } ) 
439+         } ; 
440+ 
441+         // Send the interrupt handle to the GDB thread if debugging is enabled 
442+         // This is used to allow the GDB thread to stop the vCPU 
443+         #[ cfg( gdb) ]  
444+         hv. send_dbg_msg ( DebugResponse :: InterruptHandle ( interrupt_handle) ) ?; 
445+ 
446+         Ok ( hv) 
436447    } 
437448
438449    #[ instrument( err( Debug ) ,  skip_all,  parent = Span :: current( ) ,  level = "Trace" ) ]  
@@ -634,6 +645,14 @@ impl Hypervisor for HypervLinuxDriver {
634645                    e
635646                ) 
636647            } ) ?; 
648+         #[ cfg( not( gdb) ) ]  
649+         let  debug_interrupt = false ; 
650+         #[ cfg( gdb) ]  
651+         let  debug_interrupt = self 
652+             . interrupt_handle 
653+             . debug_interrupt 
654+             . load ( Ordering :: Relaxed ) ; 
655+ 
637656        // Don't run the vcpu if `cancel_requested` is true 
638657        // 
639658        // Note: if a `InterruptHandle::kill()` called while this thread is **here** 
@@ -642,6 +661,7 @@ impl Hypervisor for HypervLinuxDriver {
642661            . interrupt_handle 
643662            . cancel_requested 
644663            . load ( Ordering :: Relaxed ) 
664+             || debug_interrupt
645665        { 
646666            Err ( MshvError :: Errno ( vmm_sys_util:: errno:: Error :: new ( 
647667                libc:: EINTR , 
@@ -667,6 +687,11 @@ impl Hypervisor for HypervLinuxDriver {
667687            . interrupt_handle 
668688            . cancel_requested 
669689            . load ( Ordering :: Relaxed ) ; 
690+         #[ cfg( gdb) ]  
691+         let  debug_interrupt = self 
692+             . interrupt_handle 
693+             . debug_interrupt 
694+             . load ( Ordering :: Relaxed ) ; 
670695        // Note: if a `InterruptHandle::kill()` called while this thread is **here** 
671696        // Then `cancel_requested` will be set to true again, which will cancel the **next vcpu run**. 
672697        // Additionally signals will be sent to this thread until `running` is set to false. 
@@ -754,27 +779,23 @@ impl Hypervisor for HypervLinuxDriver {
754779            Err ( e)  => match  e. errno ( )  { 
755780                // we send a signal to the thread to cancel execution this results in EINTR being returned by KVM so we return Cancelled 
756781                libc:: EINTR  => { 
757-                     // If cancellation was not requested for this specific vm, the vcpu was interrupted because of stale signal  
758-                     // that was  meant to be delivered to a previous/other vcpu on this same thread, so let's ignore it 
782+                     // If cancellation was not requested for this specific vm, the vcpu was interrupted because of debug interrupt or  
783+                     // a stale signal that  meant to be delivered to a previous/other vcpu on this same thread, so let's ignore it 
759784                    if  cancel_requested { 
760785                        self . interrupt_handle 
761786                            . cancel_requested 
762787                            . store ( false ,  Ordering :: Relaxed ) ; 
763788                        HyperlightExit :: Cancelled ( ) 
764789                    }  else  { 
765-                         // In case of the gdb feature, if no cancellation was requested, 
766-                         // and the debugging is enabled it means the vCPU was stopped because 
767-                         // of an interrupt coming from the debugger thread 
768790                        #[ cfg( gdb) ]  
769-                         if  self . debug . is_some ( )  { 
791+                         if  debug_interrupt { 
792+                             self . interrupt_handle 
793+                                 . debug_interrupt 
794+                                 . store ( false ,  Ordering :: Relaxed ) ; 
795+ 
770796                            // If the vCPU was stopped because of an interrupt, we need to 
771797                            // return a special exit reason so that the gdb thread can handle it 
772798                            // and resume execution 
773-                             // NOTE: There is a chance that the vCPU was stopped because of a stale 
774-                             // signal that was meant to be delivered to a previous/other vCPU on this 
775-                             // same thread, however, we cannot distinguish between the two cases, so 
776-                             // we assume that the vCPU was stopped because of an interrupt. 
777-                             // This is fine, because the debugger will be notified about an interrupt 
778799                            HyperlightExit :: Debug ( VcpuStopReason :: Interrupt ) 
779800                        }  else  { 
780801                            HyperlightExit :: Retry ( ) 
0 commit comments