Skip to content

Commit ed878a1

Browse files
committed
refactor: merge run_on_thread_local into signal handler
Merge run_on_thread_local into signal handler since it is only used there. The error returned from run_on_thread_local was ignored, so instead replace it with logic to only use vcpu ptr if TLS is initialized, without returning any errors. The reason for not asserting on TLS being initialized here is that during Firecracker shutdown, vcpus will be destroyed and TLS will be reset. If signal will be send to Firecracker during that time, the TLS accessed from a signal handler will be empty. But this is expected, so no assertions/panics are needed. Because Rust is a good language, it does not allow to reference TLS_VCPU_PTR definded inside impl block inside the signal_handler function. So move the TLS_VCPU_PTR definition outside the Vcpu impl block. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 23ccb1a commit ed878a1

File tree

1 file changed

+14
-66
lines changed

1 file changed

+14
-66
lines changed

src/vmm/src/vstate/vcpu.rs

Lines changed: 14 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ pub enum CopyKvmFdError {
8888
CreateVcpuError(#[from] kvm_ioctls::Error),
8989
}
9090

91+
thread_local!(static TLS_VCPU_PTR: VcpuCell = const { Cell::new(None) });
92+
9193
/// A wrapper around creating and using a vcpu.
9294
#[derive(Debug)]
9395
pub struct Vcpu {
@@ -110,61 +112,35 @@ pub struct Vcpu {
110112
}
111113

112114
impl Vcpu {
113-
thread_local!(static TLS_VCPU_PTR: VcpuCell = const { Cell::new(None) });
114-
115115
/// Associates `self` with the current thread.
116116
///
117117
/// It is a prerequisite to successfully run `init_thread_local_data()` before using
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-
Self::TLS_VCPU_PTR.with(|cell: &VcpuCell| {
121+
TLS_VCPU_PTR.with(|cell: &VcpuCell| {
122122
assert!(cell.get().is_none());
123123
cell.set(Some(self as *mut Vcpu));
124124
})
125125
}
126126

127-
/// Runs `func` for the `Vcpu` associated with the current thread.
128-
///
129-
/// It requires that `init_thread_local_data()` was run on this thread.
130-
///
131-
/// Fails if there is no `Vcpu` associated with the current thread.
132-
///
133-
/// # Safety
134-
///
135-
/// This is marked unsafe as it allows temporary aliasing through
136-
/// dereferencing from pointer an already borrowed `Vcpu`.
137-
unsafe fn run_on_thread_local<F>(func: F) -> Result<(), VcpuError>
138-
where
139-
F: FnOnce(&mut Vcpu),
140-
{
141-
Self::TLS_VCPU_PTR.with(|cell: &VcpuCell| {
142-
if let Some(vcpu_ptr) = cell.get() {
143-
// SAFETY: Dereferencing here is safe since `TLS_VCPU_PTR` is populated/non-empty,
144-
// and it is being cleared on `Vcpu::drop` so there is no dangling pointer.
145-
let vcpu_ref = unsafe { &mut *vcpu_ptr };
146-
func(vcpu_ref);
147-
Ok(())
148-
} else {
149-
Err(VcpuError::VcpuTlsNotPresent)
150-
}
151-
})
152-
}
153-
154127
/// Registers a signal handler which makes use of TLS and kvm immediate exit to
155128
/// kick the vcpu running on the current thread, if there is one.
156129
fn register_kick_signal_handler(&mut self) {
157130
self.init_thread_local_data();
158131

159132
extern "C" fn handle_signal(_: c_int, _: *mut siginfo_t, _: *mut c_void) {
160-
// SAFETY: This is safe because it's temporarily aliasing the `Vcpu` object, but we are
161-
// only reading `vcpu.fd` which does not change for the lifetime of the `Vcpu`.
162-
unsafe {
163-
let _ = Vcpu::run_on_thread_local(|vcpu| {
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+
164140
vcpu.kvm_vcpu.fd.set_kvm_immediate_exit(1);
165141
fence(Ordering::Release);
166-
});
167-
}
142+
}
143+
})
168144
}
169145

170146
register_signal_handler(sigrtmin() + VCPU_RTSIG_OFFSET, handle_signal)
@@ -599,12 +575,12 @@ fn handle_kvm_exit(
599575
#[cfg(not(test))]
600576
impl Drop for Vcpu {
601577
fn drop(&mut self) {
602-
Self::TLS_VCPU_PTR.with(|cell| {
578+
TLS_VCPU_PTR.with(|cell| {
603579
let vcpu_ptr = cell.get().unwrap();
604580
assert!(std::ptr::eq(vcpu_ptr, self));
605581
// Have to do this trick because `update` method is
606582
// not stable on Cell.
607-
Self::TLS_VCPU_PTR.with(|cell| cell.take());
583+
TLS_VCPU_PTR.with(|cell| cell.take());
608584
})
609585
}
610586
}
@@ -1009,34 +985,6 @@ pub(crate) mod tests {
1009985
assert!(vcpu.kvm_vcpu.peripherals.mmio_bus.is_some());
1010986
}
1011987

1012-
#[test]
1013-
fn test_vcpu_tls() {
1014-
let (_, _, mut vcpu) = setup_vcpu(0x1000);
1015-
1016-
// Running on the TLS vcpu should fail before we actually initialize it.
1017-
unsafe {
1018-
Vcpu::run_on_thread_local(|_| ()).unwrap_err();
1019-
}
1020-
1021-
// Initialize vcpu TLS.
1022-
vcpu.init_thread_local_data();
1023-
1024-
// Validate TLS vcpu is the local vcpu by changing the `id` then validating against
1025-
// the one in TLS.
1026-
vcpu.kvm_vcpu.index = 12;
1027-
unsafe {
1028-
Vcpu::run_on_thread_local(|v| assert_eq!(v.kvm_vcpu.index, 12)).unwrap();
1029-
}
1030-
1031-
// Reset vcpu TLS.
1032-
Vcpu::TLS_VCPU_PTR.with(|cell| cell.take());
1033-
1034-
// Running on the TLS vcpu after TLS reset should fail.
1035-
unsafe {
1036-
Vcpu::run_on_thread_local(|_| ()).unwrap_err();
1037-
}
1038-
}
1039-
1040988
#[test]
1041989
#[should_panic]
1042990
fn test_tls_double_init() {

0 commit comments

Comments
 (0)