Skip to content

Commit b4e2b0b

Browse files
n0toosefogti
authored andcommitted
fix(musl): add pthread workaround
Co-authored-by: Panagiotis "Ivory" Vasilopoulos <git@n0toose.net> Co-authored-by: Ellen Emilia Anna Zscheile <fogti+devel@ytrizja.de>
1 parent 026b2d0 commit b4e2b0b

File tree

3 files changed

+25
-4
lines changed

3 files changed

+25
-4
lines changed

src/linux/gdb/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use self::breakpoints::SwBreakpoints;
2424
use crate::{
2525
HypervisorError, HypervisorResult,
2626
arch::x86_64::{registers::debug::HwBreakpoints, virt_to_phys},
27-
linux::{KickSignal, x86_64::kvm_cpu::KvmVm},
27+
linux::{KickSignal, PthreadWrapper, x86_64::kvm_cpu::KvmVm},
2828
vcpu::{VcpuStopReason, VirtualCPU},
2929
vm::UhyveVm,
3030
};
@@ -218,15 +218,15 @@ impl run_blocking::BlockingEventLoop for UhyveGdbEventLoop {
218218
static SPAWN_THREAD: Once = Once::new();
219219

220220
SPAWN_THREAD.call_once(|| {
221-
let parent_thread = pthread_self();
221+
let parent_thread = PthreadWrapper(pthread_self());
222222
let mut conn_clone = conn.try_clone().unwrap();
223223
thread::spawn(move || {
224224
loop {
225225
// Block on TCP stream without consuming any data.
226226
Read::read(&mut conn_clone, &mut []).unwrap();
227227

228228
// Kick VCPU out of KVM_RUN
229-
KickSignal::pthread_kill(parent_thread).unwrap();
229+
KickSignal::pthread_kill(parent_thread.0).unwrap();
230230

231231
// Wait for all inputs to be processed and for VCPU to be running again
232232
thread::sleep(Duration::from_millis(20));

src/linux/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,23 @@ static KVM: LazyLock<Kvm> = LazyLock::new(|| Kvm::new().unwrap());
3434
/// It is used to stop a vCPU from another thread.
3535
pub(crate) struct KickSignal;
3636

37+
/// A way of sending pthread IDs reliably across threads.
38+
///
39+
/// # Platform-specific behavior
40+
///
41+
/// This is particularly necessary for musl, as `Pthread` is equal to `*mut c_void` there,
42+
/// which can't be passed to thread as easily
43+
///
44+
/// # Safety
45+
///
46+
/// This can be safely sent across threads because pthread IDs are just opaque identifiers
47+
/// and thread-safety is ensured by the pthread library.
48+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
49+
pub(crate) struct PthreadWrapper(pub Pthread);
50+
51+
unsafe impl Send for PthreadWrapper {}
52+
unsafe impl Sync for PthreadWrapper {}
53+
3754
// TODO: nix::signal::Signal doesn't support real-time signals yet.
3855
// Start using the Signal type once this no longer is the case.
3956
//

src/vm.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,11 @@ impl<VirtBackend: VirtualizationBackend> UhyveVm<VirtBackend> {
394394

395395
trace!("Killing all threads");
396396
for thread in &threads {
397-
KickSignal::pthread_kill(thread.as_pthread_t()).unwrap();
397+
// The following `as _` is necessary because on some platforms, the type (aliases)
398+
// - std::os::unix::thread::RawPthread, and
399+
// - libc::pthread_t
400+
// can differ, and currently do so on x86_64-linux-musl.
401+
KickSignal::pthread_kill(thread.as_pthread_t() as _).unwrap();
398402
}
399403

400404
let cpu_results = threads

0 commit comments

Comments
 (0)