kernel_api/detect/
cache.rs

1use core::sync::atomic::{AtomicUsize, Ordering};
2use crate::detect::Feature;
3
4static CACHE: AtomicUsize = AtomicUsize::new(0);
5
6const CAPACITY: usize = (core::mem::size_of::<usize>() * 8 - 1);
7const INIT_BIT: usize = 1 << CAPACITY;
8const INIT_MASK: usize = INIT_BIT - 1;
9
10pub struct Initializer(usize);
11
12impl Initializer {
13	pub const fn new() -> Self { Self(0) }
14	
15	pub fn set(&mut self, feature: Feature) {
16		let bit = feature as usize;
17		debug_assert!(
18			bit < CAPACITY,
19			"Too many features",
20		);
21		
22		self.0 |= 1 << bit;
23	}
24}
25
26#[cold]
27fn detect_and_initialize() {
28	debug_assert_eq!(
29		CACHE.load(Ordering::Relaxed) & INIT_MASK,
30		0,
31		"Cache is already initialised"
32	);
33
34	let features = super::detect();
35	CACHE.store(features.0 | INIT_BIT, Ordering::Relaxed);
36}
37
38pub fn test(feature: Feature) -> bool {
39	let mut cache = CACHE.load(Ordering::Relaxed);
40	let feature = feature as usize;
41
42	debug_assert!(
43		feature < CAPACITY,
44		"Too many features",
45	);
46	
47	if cache & INIT_MASK == 0 {
48		detect_and_initialize();
49		cache = CACHE.load(Ordering::Relaxed);
50	}
51	cache & (1 << feature) != 0
52}