obkrnl/proc/
cell.rs

1use super::Thread;
2use crate::context::{BorrowedArc, current_thread};
3use core::cell::Cell;
4
5/// Encapsulates a field of [Thread] that can only be accessed by the CPU that currently executing
6/// the thread.
7///
8/// # Context safety
9/// [`Default`] implementation of this type does not require a CPU context as long as implementation
10/// on `T` does not.
11#[derive(Default)]
12pub struct PrivateCell<T>(T);
13
14impl<T> PrivateCell<T> {
15    fn validate(&self, owner: &Thread) {
16        // This check will optimized out for most of the time due to the implementation of
17        // current_thread() use "pure" + "nomem" on inline assembly.
18        let current = current_thread();
19
20        if !core::ptr::eq(BorrowedArc::as_ptr(&current), owner) {
21            panic!("accessing a private cell from the other thread is not supported");
22        }
23    }
24}
25
26impl<T> PrivateCell<Cell<T>> {
27    /// See [set] for a safe wrapper.
28    ///
29    /// # Safety
30    /// `owner` must be an owner of this field.
31    ///
32    /// # Panics
33    /// If `owner` is not the current thread.
34    pub unsafe fn set(&self, owner: &Thread, v: T) {
35        self.validate(owner);
36        self.0.set(v);
37    }
38}
39
40impl<T: Copy> PrivateCell<Cell<T>> {
41    /// See [get] for a safe wrapper.
42    ///
43    /// # Safety
44    /// `owner` must be an owner of this field.
45    ///
46    /// # Panics
47    /// If `owner` is not the current thread.
48    pub unsafe fn get(&self, owner: &Thread) -> T {
49        self.validate(owner);
50        self.0.get()
51    }
52}
53
54unsafe impl<T: Send> Sync for PrivateCell<T> {}
55
56/// Safe wrapper of [PrivateCell::set()].
57macro_rules! set {
58    ($t:ident, $f:ident, $v:expr) => {
59        // SAFETY: $t is an owner of $f.
60        unsafe { $t.$f.set($t, $v) }
61    };
62}
63
64/// Safe wrapper of [PrivateCell::get()].
65macro_rules! get {
66    ($t:ident, $f:ident) => {
67        // SAFETY: $t is an owner of $f.
68        unsafe { $t.$f.get($t) }
69    };
70}
71
72pub(super) use get;
73pub(super) use set;