#[inline]
pub fn current_hint(num_shards: usize) -> usize {
if num_shards <= 1 {
return 0;
}
raw_cpu() % num_shards
}
#[inline]
fn raw_cpu() -> usize {
#[cfg(all(
target_os = "linux",
any(target_arch = "x86_64", target_arch = "aarch64")
))]
{
if let Some(cpu) = linux_rseq::cpu_id_start() {
return cpu;
}
}
0
}
#[cfg(all(
target_os = "linux",
any(target_arch = "x86_64", target_arch = "aarch64")
))]
mod linux_rseq {
use core::sync::atomic::{AtomicU8, AtomicUsize, Ordering};
#[repr(C, align(32))]
struct Rseq {
cpu_id_start: u32,
cpu_id: u32,
rseq_cs: u64,
flags: u32,
}
static STATE: AtomicU8 = AtomicU8::new(0);
static OFFSET: AtomicUsize = AtomicUsize::new(0);
#[inline]
pub fn cpu_id_start() -> Option<usize> {
let offset = match STATE.load(Ordering::Relaxed) {
1 => OFFSET.load(Ordering::Relaxed),
2 => return None,
_ => resolve()?,
};
let ptr = thread_pointer().wrapping_add(offset) as *const Rseq;
let cpu = unsafe { core::ptr::addr_of!((*ptr).cpu_id_start).read() };
Some(cpu as usize)
}
#[cold]
fn resolve() -> Option<usize> {
extern "C" {
#[link_name = "__rseq_offset"]
static RSEQ_OFFSET: isize;
}
let offset = unsafe { RSEQ_OFFSET } as usize;
if offset == 0 {
STATE.store(2, Ordering::Relaxed);
return None;
}
OFFSET.store(offset, Ordering::Relaxed);
STATE.store(1, Ordering::Relaxed);
Some(offset)
}
#[inline]
fn thread_pointer() -> usize {
let tp: usize;
unsafe {
#[cfg(target_arch = "x86_64")]
core::arch::asm!("mov {}, fs:0", out(reg) tp, options(nostack, preserves_flags, readonly));
#[cfg(target_arch = "aarch64")]
core::arch::asm!("mrs {}, tpidr_el0", out(reg) tp, options(nostack, preserves_flags, nomem));
}
tp
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn single_shard_is_always_zero() {
assert_eq!(current_hint(1), 0);
assert_eq!(current_hint(0), 0);
}
#[test]
fn hint_in_range() {
for shards in [2usize, 4, 8, 64] {
let h = current_hint(shards);
assert!(h < shards, "hint {h} out of range for {shards} shards");
}
}
}