kernel_api/detect/
cache.rs1use 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}