starnix_core/task/
kernel_threads.rs1use crate::execution::create_kernel_thread;
6use crate::task::dynamic_thread_spawner::DynamicThreadSpawner;
7use crate::task::{CurrentTask, DelayedReleaser, Kernel, Task, ThreadGroup};
8use fragile::Fragile;
9use fuchsia_async as fasync;
10use fuchsia_sync::Completion;
11use pin_project::pin_project;
12use scopeguard::ScopeGuard;
13
14use starnix_task_command::TaskCommand;
15
16use starnix_uapi::errors::Errno;
17use starnix_uapi::{errno, error};
18use std::future::Future;
19use std::pin::Pin;
20use std::sync::{Arc, OnceLock, Weak};
21use std::task::{Context, Poll};
22
23pub struct KernelThreads {
27 pub starnix_process: zx::Process,
30
31 ehandle: fasync::EHandle,
36
37 spawner: OnceLock<DynamicThreadSpawner>,
39
40 system_task: OnceLock<SystemTask>,
42
43 kernel: Weak<Kernel>,
45
46 rcu_advancer: OnceLock<RcuAdvancer>,
48}
49
50const RCU_RATE_LIMIT: std::time::Duration = std::time::Duration::from_millis(10);
53
54struct RcuAdvancer {
55 stop: Arc<Completion>,
56 thread: Option<std::thread::JoinHandle<()>>,
57}
58
59impl Drop for RcuAdvancer {
60 fn drop(&mut self) {
61 self.stop.signal();
62 fuchsia_rcu::rcu_advancer_wake();
63 if let Some(thread) = self.thread.take() {
64 let _ = thread.join();
65 }
66 }
67}
68
69impl KernelThreads {
70 pub fn new(kernel: Weak<Kernel>) -> Self {
77 KernelThreads {
78 starnix_process: fuchsia_runtime::process_self()
79 .duplicate_handle(zx::Rights::SAME_RIGHTS)
80 .expect("Failed to duplicate process self"),
81 ehandle: fasync::EHandle::local(),
82 spawner: Default::default(),
83 system_task: Default::default(),
84 kernel,
85 rcu_advancer: Default::default(),
86 }
87 }
88
89 pub fn init(&self, system_task: CurrentTask) -> Result<(), Errno> {
93 self.system_task.set(SystemTask::new(system_task)).map_err(|_| errno!(EEXIST))?;
94 self.spawner
95 .set(DynamicThreadSpawner::new(2, self.system_task().weak_task(), "kthreadd/init"))
96 .map_err(|_| errno!(EEXIST))?;
97
98 let stop = Arc::new(Completion::new());
99 let stop_clone = Arc::clone(&stop);
100 let thread = std::thread::Builder::new()
101 .name("starnix-rcu".to_string())
102 .spawn(move || {
103 let _rcu_registration = fuchsia_rcu::register_thread();
104
105 while !stop_clone.is_signaled() {
106 fuchsia_rcu::rcu_advancer_wait_for_work();
107 while !stop_clone.is_signaled() {
108 let start = std::time::Instant::now();
109 if !fuchsia_rcu::rcu_run_callbacks() {
110 break;
111 }
112 let elapsed = start.elapsed();
113 if elapsed < RCU_RATE_LIMIT {
114 if stop_clone.wait_for(RCU_RATE_LIMIT - elapsed) {
115 break;
116 }
117 }
118 }
119 }
120 fuchsia_rcu::rcu_run_callbacks();
122 })
123 .expect("failed to spawn rcu advancer thread");
124
125 self.rcu_advancer
126 .set(RcuAdvancer { stop, thread: Some(thread) })
127 .map_err(|_| errno!(EEXIST))?;
128
129 Ok(())
130 }
131
132 pub fn spawn_future(
139 &self,
140 future: impl AsyncFnOnce() -> () + Send + 'static,
141 name: &'static str,
142 ) {
143 self.ehandle.spawn_detached(WrappedMainFuture::new(
144 self.kernel.clone(),
145 async move { fasync::Task::local(future()).await },
146 name,
147 ));
148 }
149
150 pub fn spawner(&self) -> &DynamicThreadSpawner {
154 self.spawner.get().as_ref().unwrap()
155 }
156
157 pub fn system_task(&self) -> &CurrentTask {
161 self.system_task.get().expect("KernelThreads::init must be called").system_task.get()
162 }
163
164 pub fn system_thread_group(&self) -> Arc<ThreadGroup> {
169 self.system_task
170 .get()
171 .expect("KernelThreads::init must be called")
172 .system_thread_group
173 .upgrade()
174 .expect("System task must be still alive")
175 }
176}
177
178impl Drop for KernelThreads {
179 fn drop(&mut self) {
182 if let Some(system_task) = self.system_task.take() {
183 system_task.system_task.into_inner().release(());
184 }
185 }
186}
187
188pub fn with_new_current_task<F, R>(
191 system_task: &Weak<Task>,
192 task_name: String,
193 f: F,
194) -> Result<R, Errno>
195where
196 F: FnOnce(&CurrentTask) -> R,
197{
198 let current_task = {
199 let Some(system_task) = system_task.upgrade() else {
200 return error!(ESRCH);
201 };
202 create_kernel_thread(&system_task, TaskCommand::new(task_name.as_bytes())).unwrap()
203 };
204 let result = f(¤t_task);
205 current_task.release(());
206
207 DelayedReleaser::finalize();
209
210 Ok(result)
211}
212
213struct SystemTask {
214 system_task: Fragile<CurrentTask>,
217
218 system_thread_group: Weak<ThreadGroup>,
220}
221
222impl SystemTask {
223 fn new(system_task: CurrentTask) -> Self {
224 let system_thread_group = Arc::downgrade(&system_task.thread_group());
225 Self { system_task: system_task.into(), system_thread_group }
226 }
227}
228
229#[pin_project]
232pub(crate) struct WrappedFuture<F, C: Clone> {
233 #[pin]
234 fut: F,
235 cleaner: fn(C),
236 context: ScopeGuard<C, fn(C)>,
237 name: &'static str,
238}
239
240impl<F, C: Clone> WrappedFuture<F, C> {
241 pub(crate) fn new_with_cleaner(context: C, cleaner: fn(C), fut: F, name: &'static str) -> Self {
242 Self { fut, cleaner, context: ScopeGuard::with_strategy(context, cleaner), name }
244 }
245}
246
247impl<F: Future, C: Clone> Future for WrappedFuture<F, C> {
248 type Output = F::Output;
249
250 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
251 let this = self.project();
252 fuchsia_trace::duration!(starnix_logging::CATEGORY_STARNIX, &*this.name);
253 let result = this.fut.poll(cx);
254
255 (this.cleaner)(this.context.clone());
256 result
257 }
258}
259
260type WrappedMainFuture<F> = WrappedFuture<F, Weak<Kernel>>;
261
262impl<F> WrappedMainFuture<F> {
263 fn new(kernel: Weak<Kernel>, fut: F, name: &'static str) -> Self {
264 Self::new_with_cleaner(kernel, trigger_delayed_releaser, fut, name)
265 }
266}
267
268fn trigger_delayed_releaser(kernel: Weak<Kernel>) {
269 if let Some(kernel) = kernel.upgrade() {
270 if let Some(system_task) = kernel.kthreads.system_task.get() {
271 system_task.system_task.get().trigger_delayed_releaser();
272 }
273 }
274}