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}