use core::ffi::c_void;
use super::{last_os_error, BindError};
use crate::topology::cpu::ProcessorGroupAffinity;
#[repr(C)]
struct GroupAffinity {
mask: usize,
group: u16,
reserved: [u16; 3],
}
extern "system" {
fn GetCurrentThread() -> *mut c_void;
fn SetThreadGroupAffinity(
thread: *mut c_void,
group_affinity: *const GroupAffinity,
previous_group_affinity: *mut GroupAffinity,
) -> i32;
}
pub(super) fn bind_current_thread(processor: u32) -> Result<(), BindError> {
let target = ProcessorGroupAffinity::from_processor(processor)
.ok_or(BindError::OutOfRange { processor })?;
let requested = GroupAffinity {
mask: target.mask(),
group: target.group(),
reserved: [0; 3],
};
let succeeded =
unsafe { SetThreadGroupAffinity(GetCurrentThread(), &requested, core::ptr::null_mut()) };
if succeeded == 0 {
Err(last_os_error())
} else {
Ok(())
}
}
#[cfg(test)]
pub(super) fn current_confinement() -> Vec<u32> {
extern "system" {
fn GetThreadGroupAffinity(thread: *mut c_void, group_affinity: *mut GroupAffinity) -> i32;
}
let mut affinity = GroupAffinity {
mask: 0,
group: 0,
reserved: [0; 3],
};
let succeeded = unsafe { GetThreadGroupAffinity(GetCurrentThread(), &mut affinity) };
assert_ne!(
succeeded,
0,
"GetThreadGroupAffinity failed: {:?}",
last_os_error()
);
(0..usize::BITS)
.filter(|bit| affinity.mask >> bit & 1 == 1)
.map(|bit| u32::from(affinity.group) * 64 + bit)
.collect()
}