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}