use crate::sync::internal::{AtomicBool, AtomicU64, Ordering};
pub(crate) struct Life {
detached: AtomicBool,
id: AtomicU64,
}
impl Life {
pub(crate) fn new() -> Self {
Self {
detached: AtomicBool::new(false),
id: AtomicU64::new(0),
}
}
pub(crate) fn here(&self) {
self.id.store(os_thread_id(), Ordering::Release);
}
pub(crate) fn detach(&self) {
self.detached.store(true, Ordering::Release);
}
pub(crate) fn back(&self) {
self.detached.store(false, Ordering::Release);
}
pub(crate) fn is_detached(&self) -> bool {
self.detached.load(Ordering::Acquire)
}
pub(crate) fn unpin(&self, cores: &[usize]) {
let id = self.id.load(Ordering::Acquire);
if id != 0 && !cores.is_empty() {
unpin(id, cores);
}
}
}
#[cfg(target_os = "linux")]
fn os_thread_id() -> u64 {
u64::try_from(unsafe { libc::gettid() }).unwrap_or(0)
}
#[cfg(target_os = "linux")]
fn unpin(id: u64, cores: &[usize]) {
let Ok(tid) = libc::pid_t::try_from(id) else {
return;
};
unsafe {
let mut set: libc::cpu_set_t = core::mem::zeroed();
for &core in cores {
libc::CPU_SET(core, &mut set);
}
let _ = libc::sched_setaffinity(tid, size_of::<libc::cpu_set_t>(), &set);
}
}
#[cfg(windows)]
fn os_thread_id() -> u64 {
u64::from(unsafe { crate::syscore::windows::GetCurrentThreadId() })
}
#[cfg(windows)]
fn unpin(id: u64, cores: &[usize]) {
use crate::syscore::windows::{CloseHandle, OpenThread, SetThreadAffinityMask};
const ACCESS: u32 = 0x0020 | 0x0040;
let Ok(id) = u32::try_from(id) else {
return;
};
let mask = cores
.iter()
.filter(|&&core| core < usize::BITS as usize)
.fold(0usize, |mask, &core| mask | (1 << core));
unsafe {
let thread = OpenThread(ACCESS, 0, id);
if !thread.is_null() {
SetThreadAffinityMask(thread, mask);
CloseHandle(thread);
}
}
}
#[cfg(not(any(target_os = "linux", windows)))]
fn os_thread_id() -> u64 {
0
}
#[cfg(not(any(target_os = "linux", windows)))]
fn unpin(_id: u64, _cores: &[usize]) {}