55// Use of this source code is governed by a BSD-style license that can be 
66// found in the THIRD-PARTY file. 
77
8- use  std:: cell:: Cell ; 
8+ use  std:: cell:: RefCell ; 
99#[ cfg( feature = "gdb" ) ]  
1010use  std:: os:: fd:: AsRawFd ; 
1111use  std:: sync:: atomic:: { Ordering ,  fence} ; 
@@ -14,9 +14,9 @@ use std::sync::{Arc, Barrier};
1414use  std:: { fmt,  io,  thread} ; 
1515
1616use  kvm_bindings:: { KVM_SYSTEM_EVENT_RESET ,  KVM_SYSTEM_EVENT_SHUTDOWN } ; 
17- use  kvm_ioctls:: VcpuExit ; 
1817#[ cfg( feature = "gdb" ) ]  
1918use  kvm_ioctls:: VcpuFd ; 
19+ use  kvm_ioctls:: { KvmRunWrapper ,  VcpuExit } ; 
2020use  libc:: { c_int,  c_void,  siginfo_t} ; 
2121use  log:: { error,  info,  warn} ; 
2222use  vmm_sys_util:: errno; 
@@ -69,9 +69,6 @@ pub struct VcpuConfig {
6969     pub  cpu_config :  CpuConfiguration , 
7070} 
7171
72- // Using this for easier explicit type-casting to help IDEs interpret the code. 
73- type  VcpuCell  = Cell < Option < * mut  Vcpu > > ; 
74- 
7572/// Error type for [`Vcpu::start_threaded`]. 
7673#[ derive( Debug ,  derive_more:: From ,  thiserror:: Error ) ]  
7774#[ error( "Failed to spawn vCPU thread: {0}" ) ]  
@@ -88,7 +85,10 @@ pub enum CopyKvmFdError {
8885     CreateVcpuError ( #[ from]   kvm_ioctls:: Error ) , 
8986} 
9087
91- thread_local ! ( static  TLS_VCPU_PTR :  VcpuCell  = const  {  Cell :: new( None )  } ) ; 
88+ // Stores the mmap region of `kvm_run` struct for the current Vcpu. This allows for the 
89+ // signal handler to safely access the `kvm_run` even when Vcpu is dropped and vcpu fd 
90+ // is closed. 
91+ thread_local ! ( static  TLS_VCPU_PTR :  RefCell <Option <KvmRunWrapper >> = const  {  RefCell :: new( None )  } ) ; 
9292
9393/// A wrapper around creating and using a vcpu. 
9494#[ derive( Debug ) ]  
@@ -118,9 +118,16 @@ impl Vcpu {
118118     /// `run_on_thread_local()` on the current thread. 
119119     /// This function will panic if there already is a `Vcpu` present in the TLS. 
120120     fn  init_thread_local_data ( & mut  self )  { 
121-         TLS_VCPU_PTR . with ( |cell :  & VcpuCell | { 
122-             assert ! ( cell. get( ) . is_none( ) ) ; 
123-             cell. set ( Some ( self  as  * mut  Vcpu ) ) ; 
121+         // Use of `kvm_run` size here is safe because we only 
122+         // care about `immediate_exit` field which is at byte offset of 2. 
123+         let  kvm_run_ptr = KvmRunWrapper :: mmap_from_fd ( 
124+             & self . kvm_vcpu . fd , 
125+             std:: mem:: size_of :: < kvm_bindings:: kvm_run > ( ) , 
126+         ) 
127+         . unwrap ( ) ; 
128+         TLS_VCPU_PTR . with ( |cell| { 
129+             assert ! ( cell. borrow( ) . is_none( ) ) ; 
130+             * cell. borrow_mut ( )  = Some ( kvm_run_ptr) ; 
124131        } ) 
125132    } 
126133
@@ -130,14 +137,9 @@ impl Vcpu {
130137        self . init_thread_local_data ( ) ; 
131138
132139        extern  "C"  fn  handle_signal ( _:  c_int ,  _:  * mut  siginfo_t ,  _:  * mut  c_void )  { 
133-             TLS_VCPU_PTR . with ( |cell :  & VcpuCell | { 
134-                 if  let  Some ( vcpu_ptr)  = cell. get ( )  { 
135-                     // SAFETY: Dereferencing here is safe since `TLS_VCPU_PTR` is 
136-                     // populated/non-empty, and it is being cleared on 
137-                     // `Vcpu::drop` so there is no dangling pointer. 
138-                     let  vcpu = unsafe  {  & mut  * vcpu_ptr } ; 
139- 
140-                     vcpu. kvm_vcpu . fd . set_kvm_immediate_exit ( 1 ) ; 
140+             TLS_VCPU_PTR . with ( |cell| { 
141+                 if  let  Some ( kvm_run_ptr)  = & mut  * cell. borrow_mut ( )  { 
142+                     kvm_run_ptr. as_mut_ref ( ) . immediate_exit  = 1 ; 
141143                    fence ( Ordering :: Release ) ; 
142144                } 
143145            } ) 
@@ -569,28 +571,6 @@ fn handle_kvm_exit(
569571    } 
570572} 
571573
572- impl  Drop  for  Vcpu  { 
573-     fn  drop ( & mut  self )  { 
574-         TLS_VCPU_PTR . with ( |cell| { 
575-             // The reason for not asserting TLS being set here is that 
576-             // it can happen that Vcpu::Drop is called on vcpus which never were 
577-             // put on their threads. This can happen if some error occurs during Vmm 
578-             // setup before `start_threaded` call. 
579-             if  let  Some ( _vcpu_ptr)  = cell. get ( )  { 
580-                 // During normal runtime there is a strong assumption that vcpus will be 
581-                 // put on their own threads, thus TLS will be initialized with the 
582-                 // correct pointer. 
583-                 // In test we do not put vcpus on separate threads, so TLS will have a value 
584-                 // of the last created vcpu. 
585-                 #[ cfg( not( test) ) ]  
586-                 assert ! ( std:: ptr:: eq( _vcpu_ptr,  self ) ) ; 
587- 
588-                 TLS_VCPU_PTR . take ( ) ; 
589-             } 
590-         } ) 
591-     } 
592- } 
593- 
594574/// List of events that the Vcpu can receive. 
595575#[ derive( Debug ,  Clone ) ]  
596576pub  enum  VcpuEvent  { 
0 commit comments