Skip to main content

starnix_core/task/
kernel_threads.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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 pin_project::pin_project;
11use scopeguard::ScopeGuard;
12
13use starnix_task_command::TaskCommand;
14
15use starnix_uapi::errors::Errno;
16use starnix_uapi::{errno, error};
17use std::future::Future;
18use std::pin::Pin;
19use std::sync::{Arc, OnceLock, Weak};
20use std::task::{Context, Poll};
21
22/// The threads that the kernel runs internally.
23///
24/// These threads run in the main starnix process and outlive any specific userspace process.
25pub struct KernelThreads {
26    /// The main starnix process. This process is used to create new processes when using the
27    /// restricted executor.
28    pub starnix_process: zx::Process,
29
30    /// A handle to the async executor running in `starnix_process`.
31    ///
32    /// You can spawn tasks on this executor using `spawn_future`. However, those task must not
33    /// block. If you need to block, you can spawn a worker thread using `spawner`.
34    ehandle: fasync::EHandle,
35
36    /// The thread pool to spawn blocking calls to.
37    spawner: OnceLock<DynamicThreadSpawner>,
38
39    /// Information about the main system task that is bound to the kernel main thread.
40    system_task: OnceLock<SystemTask>,
41
42    /// A weak reference to the kernel owning this struct.
43    kernel: Weak<Kernel>,
44}
45
46impl KernelThreads {
47    /// Create a KernelThreads object for the given Kernel.
48    ///
49    /// Must be called in the initial Starnix process on a thread with an async executor. This
50    /// function captures the async executor for this thread for use with spawned futures.
51    ///
52    /// Used during kernel boot.
53    pub fn new(kernel: Weak<Kernel>) -> Self {
54        KernelThreads {
55            starnix_process: fuchsia_runtime::process_self()
56                .duplicate_handle(zx::Rights::SAME_RIGHTS)
57                .expect("Failed to duplicate process self"),
58            ehandle: fasync::EHandle::local(),
59            spawner: Default::default(),
60            system_task: Default::default(),
61            kernel,
62        }
63    }
64
65    /// Initialize this object with the system task that will be used for spawned threads.
66    ///
67    /// This function must be called before this object is used to spawn threads.
68    pub fn init(&self, system_task: CurrentTask) -> Result<(), Errno> {
69        self.system_task.set(SystemTask::new(system_task)).map_err(|_| errno!(EEXIST))?;
70        self.spawner
71            .set(DynamicThreadSpawner::new(2, self.system_task().weak_task(), "kthreadd/init"))
72            .map_err(|_| errno!(EEXIST))?;
73        Ok(())
74    }
75
76    /// Spawn an async task in the main async executor to await the given future.
77    ///
78    /// Use this function to run async tasks in the background. These tasks cannot block or else
79    /// they will starve the main async executor.
80    ///
81    /// Prefer this function to `spawn` for non-blocking work.
82    pub fn spawn_future(
83        &self,
84        future: impl AsyncFnOnce() -> () + Send + 'static,
85        name: &'static str,
86    ) {
87        self.ehandle.spawn_detached(WrappedMainFuture::new(
88            self.kernel.clone(),
89            async move { fasync::Task::local(future()).await },
90            name,
91        ));
92    }
93
94    /// The dynamic thread spawner used to spawn threads.
95    ///
96    /// To spawn a thread in this thread pool, use `spawn()`.
97    pub fn spawner(&self) -> &DynamicThreadSpawner {
98        self.spawner.get().as_ref().unwrap()
99    }
100
101    /// Access the `CurrentTask` for the kernel main thread.
102    ///
103    /// This function can only be called from the kernel main thread itself.
104    pub fn system_task(&self) -> &CurrentTask {
105        self.system_task.get().expect("KernelThreads::init must be called").system_task.get()
106    }
107
108    /// Access the `ThreadGroup` for the system tasks.
109    ///
110    /// This function can be safely called from anywhere as soon as `KernelThreads::init` has been
111    /// called.
112    pub fn system_thread_group(&self) -> Arc<ThreadGroup> {
113        self.system_task
114            .get()
115            .expect("KernelThreads::init must be called")
116            .system_thread_group
117            .upgrade()
118            .expect("System task must be still alive")
119    }
120}
121
122impl Drop for KernelThreads {
123    // TODO: Replace with .release. This is not actually safe, since locks
124    // may be held elsewhere on this thread.
125    fn drop(&mut self) {
126        if let Some(system_task) = self.system_task.take() {
127            system_task.system_task.into_inner().release(());
128        }
129    }
130}
131
132/// Create a new system task, register it on the thread and run the given closure with it.
133
134pub fn with_new_current_task<F, R>(
135    system_task: &Weak<Task>,
136    task_name: String,
137    f: F,
138) -> Result<R, Errno>
139where
140    F: FnOnce(&CurrentTask) -> R,
141{
142    let current_task = {
143        let Some(system_task) = system_task.upgrade() else {
144            return error!(ESRCH);
145        };
146        create_kernel_thread(&system_task, TaskCommand::new(task_name.as_bytes())).unwrap()
147    };
148    let result = f(&current_task);
149    current_task.release(());
150
151    // Ensure that no releasables are registered after this point as we unwind the stack.
152    DelayedReleaser::finalize();
153
154    Ok(result)
155}
156
157struct SystemTask {
158    /// The system task is bound to the kernel main thread. `Fragile` ensures a runtime crash if it
159    /// is accessed from any other thread.
160    system_task: Fragile<CurrentTask>,
161
162    /// The system `ThreadGroup` is accessible from everywhere.
163    system_thread_group: Weak<ThreadGroup>,
164}
165
166impl SystemTask {
167    fn new(system_task: CurrentTask) -> Self {
168        let system_thread_group = Arc::downgrade(&system_task.thread_group());
169        Self { system_task: system_task.into(), system_thread_group }
170    }
171}
172
173// The order is important here. Rust will drop fields in declaration order and we want
174// the future to be dropped before the ScopeGuard runs.
175#[pin_project]
176pub(crate) struct WrappedFuture<F, C: Clone> {
177    #[pin]
178    fut: F,
179    cleaner: fn(C),
180    context: ScopeGuard<C, fn(C)>,
181    name: &'static str,
182}
183
184impl<F, C: Clone> WrappedFuture<F, C> {
185    pub(crate) fn new_with_cleaner(context: C, cleaner: fn(C), fut: F, name: &'static str) -> Self {
186        // We need the ScopeGuard in case the future queues releasers when dropped.
187        Self { fut, cleaner, context: ScopeGuard::with_strategy(context, cleaner), name }
188    }
189}
190
191impl<F: Future, C: Clone> Future for WrappedFuture<F, C> {
192    type Output = F::Output;
193
194    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
195        let this = self.project();
196        fuchsia_trace::duration!(starnix_logging::CATEGORY_STARNIX, &*this.name);
197        let result = this.fut.poll(cx);
198
199        (this.cleaner)(this.context.clone());
200        result
201    }
202}
203
204type WrappedMainFuture<F> = WrappedFuture<F, Weak<Kernel>>;
205
206impl<F> WrappedMainFuture<F> {
207    fn new(kernel: Weak<Kernel>, fut: F, name: &'static str) -> Self {
208        Self::new_with_cleaner(kernel, trigger_delayed_releaser, fut, name)
209    }
210}
211
212fn trigger_delayed_releaser(kernel: Weak<Kernel>) {
213    if let Some(kernel) = kernel.upgrade() {
214        if let Some(system_task) = kernel.kthreads.system_task.get() {
215            system_task.system_task.get().trigger_delayed_releaser();
216        }
217    }
218}