1use std::{
2 collections::HashMap,
3 mem::MaybeUninit,
4 ptr::NonNull,
5 sync::{Arc, OnceLock},
6};
7
8use dynlink::{compartment::Compartment, tls::TlsRegion};
9use monitor_api::{RuntimeThreadControl, ThreadMgrStats, MONITOR_INSTANCE_ID};
10use twizzler_abi::{
11 object::NULLPAGE_SIZE,
12 syscall::{sys_spawn, sys_thread_exit, ThreadSyncSleep, UpcallTargetSpawnOption},
13 thread::{ExecutionState, ThreadRepr},
14 upcall::{UpcallFlags, UpcallInfo, UpcallMode, UpcallOptions, UpcallTarget},
15};
16use twizzler_rt_abi::{
17 error::{GenericError, TwzError},
18 object::{MapFlags, ObjID},
19};
20
21use super::{
22 get_monitor,
23 space::{MapHandle, MapInfo},
24};
25use crate::mon::space::Space;
26
27mod cleaner;
28pub(crate) use cleaner::ThreadCleaner;
29
30pub const SUPER_UPCALL_STACK_SIZE: usize = 8 * 1024 * 1024; pub const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024; pub const STACK_SIZE_MIN_ALIGN: usize = 0x1000; pub struct ThreadMgr {
41 all: HashMap<ObjID, ManagedThread>,
42 cleaner: OnceLock<cleaner::ThreadCleaner>,
43 next_id: u32,
44 id_stack: Vec<u32>,
45}
46
47impl Default for ThreadMgr {
48 fn default() -> Self {
49 Self {
50 all: HashMap::default(),
51 cleaner: OnceLock::new(),
52 next_id: 1,
53 id_stack: Vec::new(),
54 }
55 }
56}
57
58struct IdDropper<'a> {
59 mgr: &'a mut ThreadMgr,
60 id: u32,
61}
62
63impl<'a> IdDropper<'a> {
64 pub fn freeze(self) -> u32 {
65 let id = self.id;
66 std::mem::forget(self);
67 id
68 }
69}
70
71impl<'a> Drop for IdDropper<'a> {
72 fn drop(&mut self) {
73 self.mgr.release_super_tid(self.id);
74 }
75}
76
77impl ThreadMgr {
78 pub(super) fn set_cleaner(&mut self, cleaner: cleaner::ThreadCleaner) {
79 self.cleaner.set(cleaner).ok().unwrap();
80 }
81
82 fn next_super_tid(&mut self) -> IdDropper<'_> {
83 let id = self.id_stack.pop().unwrap_or_else(|| {
84 let id = self.next_id;
85 self.next_id += 1;
86 id
87 });
88 IdDropper { mgr: self, id }
89 }
90
91 fn release_super_tid(&mut self, id: u32) {
92 self.id_stack.push(id);
93 }
94
95 fn do_remove(&mut self, thread: &ManagedThread) {
96 self.all.remove(&thread.id);
97 self.release_super_tid(thread.super_tid);
98 if let Some(cleaner) = self.cleaner.get() {
99 cleaner.untrack(thread.id);
100 }
101 }
102
103 pub fn stat(&self) -> ThreadMgrStats {
104 ThreadMgrStats {
105 nr_threads: self.all.len(),
106 }
107 }
108
109 unsafe fn spawn_thread(
110 start: usize,
111 super_stack_start: usize,
112 super_thread_pointer: usize,
113 arg: usize,
114 self_ctx: ObjID,
115 ) -> Result<ObjID, TwzError> {
116 let mut upcall_target = UpcallTarget::new(
117 None,
118 Some(twizzler_rt_abi::arch::__twz_rt_upcall_entry),
119 super_stack_start,
120 SUPER_UPCALL_STACK_SIZE,
121 super_thread_pointer,
122 MONITOR_INSTANCE_ID,
123 self_ctx,
124 [UpcallOptions {
125 flags: UpcallFlags::empty(),
126 mode: UpcallMode::CallSuper,
127 }; UpcallInfo::NR_UPCALLS],
128 );
129
130 let mb = &mut upcall_target.options[UpcallInfo::Mailbox(0).number()];
131 mb.mode = UpcallMode::CallSelf;
132
133 sys_spawn(twizzler_abi::syscall::ThreadSpawnArgs {
134 entry: start,
135 stack_base: super_stack_start,
136 stack_size: SUPER_UPCALL_STACK_SIZE,
137 tls: super_thread_pointer,
138 arg,
139 flags: twizzler_abi::syscall::ThreadSpawnFlags::empty(),
140 vm_context_handle: None,
141 upcall_target: UpcallTargetSpawnOption::SetTo(upcall_target),
142 })
143 }
144
145 fn do_spawn(
146 &mut self,
147 monitor_dynlink_comp: &mut Compartment,
148 start: unsafe extern "C" fn(usize) -> !,
149 arg: usize,
150 main_thread_comp: Option<ObjID>,
151 instance: ObjID,
152 ) -> Result<ManagedThread, TwzError> {
153 let super_tls = monitor_dynlink_comp
154 .build_tls_region(RuntimeThreadControl::default(), |layout| unsafe {
155 NonNull::new(std::alloc::alloc_zeroed(layout))
156 })
157 .map_err(|_| GenericError::Internal)?;
158 let super_tid = self.next_super_tid().freeze();
159 unsafe {
160 let tcb = super_tls.get_thread_control_block::<RuntimeThreadControl>();
161 (*tcb).runtime_data.set_id(super_tid);
162 }
163 let super_thread_pointer = super_tls.get_thread_pointer_value();
164 let super_stack = Box::new_zeroed_slice(SUPER_UPCALL_STACK_SIZE);
165 let id = unsafe {
166 Self::spawn_thread(
167 start as *const () as usize,
168 super_stack.as_ptr() as usize,
169 super_thread_pointer,
170 arg,
171 instance,
172 )?
173 };
174 let repr = Space::map(
175 &get_monitor().space,
176 MapInfo {
177 id,
178 flags: MapFlags::READ,
179 },
180 )
181 .unwrap();
182 Ok(Arc::new(ManagedThreadInner {
183 id,
184 super_tid,
185 repr: ManagedThreadRepr::new(repr),
186 _super_stack: super_stack,
187 _super_tls: super_tls,
188 main_thread_comp,
189 }))
190 }
191
192 pub fn start_thread(
195 &mut self,
196 monitor_dynlink_comp: &mut Compartment,
197 main: Box<dyn FnOnce()>,
198 main_thread_comp: Option<ObjID>,
199 instance: ObjID,
200 ) -> Result<ManagedThread, TwzError> {
201 let main_addr = Box::into_raw(Box::new(main)) as usize;
202 unsafe extern "C" fn managed_thread_entry(main: usize) -> ! {
203 {
204 let main = Box::from_raw(main as *mut Box<dyn FnOnce()>);
205 main();
206 }
207
208 sys_thread_exit(0);
209 }
210
211 let mt = self.do_spawn(
212 monitor_dynlink_comp,
213 managed_thread_entry,
214 main_addr,
215 main_thread_comp,
216 instance,
217 );
218 if let Ok(ref mt) = mt {
219 if let Some(cleaner) = self.cleaner.get() {
220 cleaner.track(mt.clone());
221 }
222 }
223 mt
224 }
225}
226
227pub struct ManagedThreadInner {
229 pub id: ObjID,
231 pub super_tid: u32,
232 pub(crate) repr: ManagedThreadRepr,
234 _super_stack: Box<[MaybeUninit<u8>]>,
235 _super_tls: TlsRegion,
236 pub main_thread_comp: Option<ObjID>,
237}
238
239impl ManagedThreadInner {
240 pub fn has_exited(&self) -> bool {
242 self.repr.get_repr().get_state() == ExecutionState::Exited
243 }
244
245 pub fn waitable_until_exit(&self) -> ThreadSyncSleep {
247 self.repr.get_repr().waitable(ExecutionState::Exited)
248 }
249}
250
251unsafe impl Send for ManagedThreadInner {}
253unsafe impl Sync for ManagedThreadInner {}
254
255impl core::fmt::Debug for ManagedThreadInner {
256 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257 write!(f, "ManagedThread({})", self.id)
258 }
259}
260
261impl Drop for ManagedThreadInner {
262 fn drop(&mut self) {
263 tracing::trace!("dropping ManagedThread {}", self.id);
264 }
265}
266
267pub type ManagedThread = Arc<ManagedThreadInner>;
269
270pub(crate) struct ManagedThreadRepr {
272 handle: MapHandle,
273}
274
275impl ManagedThreadRepr {
276 fn new(handle: MapHandle) -> Self {
277 Self { handle }
278 }
279
280 pub fn get_repr(&self) -> &ThreadRepr {
282 let addr = self.handle.addrs().start + NULLPAGE_SIZE;
283 unsafe { (addr as *const ThreadRepr).as_ref().unwrap() }
284 }
285}