obkrnl/proc/
thread.rs

1use super::Proc;
2use super::cell::{PrivateCell, get, set};
3use crate::lock::{Gutex, GutexGroup, GutexWrite};
4use alloc::sync::Arc;
5use core::cell::Cell;
6use core::marker::PhantomData;
7use core::sync::atomic::{AtomicU8, Ordering};
8
9/// Implementation of `thread` structure.
10///
11/// All thread **must** run to completion once execution has been started otherwise resource will be
12/// leak if the thread is dropped while its execution currently in the kernel space.
13///
14/// We subtitute `TDP_NOSLEEPING` with `td_intr_nesting_level` and `td_critnest` since it is the
15/// only cases the thread should not allow to sleep.
16///
17/// Do not try to access any [RefCell](core::cell::RefCell) fields from interrupt handler because it
18/// might currently locked.
19pub struct Thread {
20    proc: Arc<Proc>,                         // td_proc
21    active_pins: AtomicU8,                   // td_critnest
22    active_interrupts: AtomicU8,             // td_intr_nesting_level
23    active_mutexes: PrivateCell<Cell<u16>>,  // td_locks
24    sleeping: Gutex<usize>,                  // td_wchan
25    profiling_ticks: PrivateCell<Cell<u32>>, // td_pticks
26    active_heap_guard: PrivateCell<Cell<usize>>,
27}
28
29impl Thread {
30    /// This function does not do anything except initialize the struct memory. It is the caller
31    /// responsibility to configure the thread after this so it have a proper states and trigger
32    /// necessary events.
33    ///
34    /// # Context safety
35    /// This function does not require a CPU context.
36    pub fn new_bare(proc: Arc<Proc>) -> Self {
37        // td_critnest on the PS4 started with 1 but this does not work in our case because we use
38        // RAII to increase and decrease it.
39        let gg = GutexGroup::new();
40
41        Self {
42            proc,
43            active_pins: AtomicU8::new(0),
44            active_interrupts: AtomicU8::new(0),
45            active_mutexes: PrivateCell::default(),
46            sleeping: gg.spawn(0),
47            profiling_ticks: PrivateCell::default(),
48            active_heap_guard: PrivateCell::default(),
49        }
50    }
51
52    pub fn can_sleep(&self) -> bool {
53        // Both of the values here can only modified by this thread so no race condition here.
54        let active_pins = self.active_pins.load(Ordering::Relaxed);
55        let active_interrupts = self.active_interrupts.load(Ordering::Relaxed);
56
57        active_pins == 0 && active_interrupts == 0
58    }
59
60    pub fn proc(&self) -> &Arc<Proc> {
61        &self.proc
62    }
63
64    /// See [`crate::context::pin_cpu()`] for a safe wrapper.
65    ///
66    /// # Safety
67    /// Once this value is zero this thread can switch to a different CPU. The code after this value
68    /// decrement must not depend on a specific CPU.
69    ///
70    /// This value must not modified by the other thread.
71    pub unsafe fn active_pins(&self) -> &AtomicU8 {
72        &self.active_pins
73    }
74
75    /// # Safety
76    /// This value can only modified by interrupt entry point.
77    pub unsafe fn active_interrupts(&self) -> &AtomicU8 {
78        &self.active_interrupts
79    }
80
81    /// # Panics
82    /// If called from the other thread.
83    pub fn active_mutexes(&self) -> u16 {
84        get!(self, active_mutexes)
85    }
86
87    /// # Panics
88    /// If called from the other thread.
89    pub fn set_active_mutexes(&self, v: u16) {
90        set!(self, active_mutexes, v)
91    }
92
93    /// Sleeping address. Zero if this thread is not in a sleep queue.
94    pub fn sleeping_mut(&self) -> GutexWrite<usize> {
95        self.sleeping.write()
96    }
97
98    /// # Panics
99    /// If called from the other thread.
100    pub fn set_profiling_ticks(&self, v: u32) {
101        set!(self, profiling_ticks, v)
102    }
103
104    /// # Panics
105    /// If called from the other thread.
106    pub fn active_heap_guard(&self) -> usize {
107        get!(self, active_heap_guard)
108    }
109
110    pub fn disable_vm_heap(&self) -> HeapGuard {
111        let v = get!(self, active_heap_guard).checked_add(1).unwrap();
112
113        set!(self, active_heap_guard, v);
114
115        HeapGuard {
116            td: self,
117            phantom: PhantomData,
118        }
119    }
120}
121
122/// RAII struct to disable VM heap for the thread.
123pub struct HeapGuard<'a> {
124    td: &'a Thread,
125    phantom: PhantomData<*const ()>, // For !Send and !Sync.
126}
127
128impl Drop for HeapGuard<'_> {
129    fn drop(&mut self) {
130        let td = self.td;
131        let v = get!(td, active_heap_guard) - 1;
132
133        set!(td, active_heap_guard, v);
134    }
135}