obkrnl/context/
local.rs

1use super::{PinnedContext, current_config, pin_cpu};
2use alloc::vec::Vec;
3use core::ops::Deref;
4
5/// Encapsulates per-CPU value.
6///
7/// `T` need to implement [Send] for this type to implement [Send] and [Sync] because its value
8/// created by one thread then access from another thread.
9///
10/// Use [RefCell](core::cell::RefCell) if you need interior mutability but it will make that value
11/// not safe to access from any interrupt handler. You can't use mutex here because once the thread
12/// is pinned it cannot go to sleep.
13pub struct CpuLocal<T>(Vec<T>);
14
15impl<T> CpuLocal<T> {
16    pub fn new(mut f: impl FnMut(usize) -> T) -> Self {
17        let len = current_config().max_cpu().get();
18        let mut vec = Vec::with_capacity(len);
19
20        for i in 0..len {
21            vec.push(f(i));
22        }
23
24        Self(vec)
25    }
26
27    /// The calling thread cannot go to sleep until the returned [`CpuLock`] is dropped. Attempt to
28    /// call any function that can put the thread to sleep will be panic.
29    pub fn lock(&self) -> CpuLock<T> {
30        let pin = pin_cpu();
31        let val = &self.0[unsafe { pin.cpu() }];
32
33        CpuLock { val, pin }
34    }
35}
36
37unsafe impl<T: Send> Send for CpuLocal<T> {}
38unsafe impl<T: Send> Sync for CpuLocal<T> {}
39
40/// RAII struct to access per-CPU value in [`CpuLocal`].
41pub struct CpuLock<'a, T> {
42    val: &'a T,
43    #[allow(dead_code)]
44    pin: PinnedContext, // Must be dropped last.
45}
46
47impl<T> Deref for CpuLock<'_, T> {
48    type Target = T;
49
50    fn deref(&self) -> &Self::Target {
51        self.val
52    }
53}