blob: a466108c916a4454f33e368c325186d0cd7c3388 [file]
// Copyright 2020 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
use core::cell::UnsafeCell;
use core::pin::Pin;
use core::ptr::NonNull;
use executor_bindings as bindings;
use pin_init::{PinInit, pin_data, pin_init};
use super::event_dispatcher::EventDispatcher;
use super::handle::{HandleOwner, HandleRef};
use super::job_dispatcher::JobDispatcher;
use super::memory_watchdog::MemoryWatchdog;
use super::root_job_observer::RootJobObserver;
/// An `Executor` encapsulates the kernel state necessary to implement the Zircon system calls. It
/// depends on an interface from the kernel below it, presenting primitives like threads and wait
/// queues. It presents an interface to the system call implementations.
///
/// The goals of factoring this into such a layer include:
///
/// - The ability to test code in this layer separately from low-level kernel implementation details,
/// and from the syscall mechanism. This includes correctness as well as performance tests.
///
/// - Centralize resource management in order to make progress on things like not reporting
/// `ZX_ERR_NO_MEMORY` when creating a `zx::event`, or reporting bad handle faults.
///
/// TODO(kulakowski) The above comment is aspirational. So far, only the root job (and its observer)
/// is managed by the `Executor`. Other subsystems, like port arenas and handle arenas, are not yet
/// included. And e.g. tests are not yet written against the `Executor`.
#[pin_data]
#[repr(C)]
pub struct Executor {
/// All jobs and processes of this `Executor` are rooted at this job.
root_job: UnsafeCell<Option<fbl::RefPtr<JobDispatcher>>>,
root_job_handle: UnsafeCell<Option<HandleOwner>>,
/// Watch the root job, taking action (such as a system reboot) if it ends up
/// with no children.
root_job_observer: UnsafeCell<Option<Pin<fbl::UniquePtr<RootJobObserver>>>>,
/// The memory watchdog for this `Executor`. When it observes low memory
/// conditions, it notifies the root job of this executor.
#[pin]
memory_watchdog: MemoryWatchdog,
}
// SAFETY: `root_job` and `root_job_handle` are initialized once in `init` before any concurrent
// access and are read-only afterwards; `root_job_observer` is initialized once in
// `start_root_job_observer` and is not accessed concurrently; `memory_watchdog` is `Sync` and
// `Send`.
unsafe impl Sync for Executor {}
// SAFETY: `Executor` can be safely transferred across threads under the same invariants as `Sync`.
unsafe impl Send for Executor {}
// Compile-time layout assertions against the C++ Executor type via bindgen.
zr::static_assert!(core::mem::size_of::<Executor>() == core::mem::size_of::<bindings::Executor>());
zr::static_assert!(
core::mem::align_of::<Executor>() == core::mem::align_of::<bindings::Executor>()
);
zr::static_assert!(
core::mem::offset_of!(Executor, root_job)
== core::mem::offset_of!(bindings::Executor, root_job_)
);
zr::static_assert!(
core::mem::offset_of!(Executor, root_job_handle)
== core::mem::offset_of!(bindings::Executor, root_job_handle_)
);
zr::static_assert!(
core::mem::offset_of!(Executor, root_job_observer)
== core::mem::offset_of!(bindings::Executor, root_job_observer_)
);
zr::static_assert!(
core::mem::offset_of!(Executor, memory_watchdog)
== core::mem::offset_of!(bindings::Executor, memory_watchdog_)
);
impl Executor {
/// Creates a new uninitialized `Executor`.
pub fn new() -> impl PinInit<Self, core::convert::Infallible> {
pin_init!(Self {
root_job: UnsafeCell::new(None),
root_job_handle: UnsafeCell::new(None),
root_job_observer: UnsafeCell::new(None),
memory_watchdog <- MemoryWatchdog::new(),
})
}
/// Initializes the executor by creating the root job and its handle.
pub fn init(&self) {
// Create root job.
let root_job = JobDispatcher::create_root_job();
// Create handle.
let root_job_handle =
HandleOwner::make_from_ref(root_job.clone(), JobDispatcher::default_rights());
assert!(root_job_handle.is_some());
// SAFETY: `init` is called once during boot before any other methods or threads access
// `self`.
unsafe {
*self.root_job_handle.get() = root_job_handle;
*self.root_job.get() = Some(root_job);
}
}
/// Returns a reference to the root job dispatcher.
pub fn get_root_job_dispatcher(&self) -> &fbl::RefPtr<JobDispatcher> {
// SAFETY: `root_job` is initialized once in `init` before any calls to this method and is
// not modified afterwards.
unsafe { (*self.root_job.get()).as_ref().unwrap() }
}
/// Returns a reference to the root job handle.
pub fn get_root_job_handle(&self) -> HandleRef<'_> {
// SAFETY: `root_job_handle` is initialized once in `init` before any calls to this method
// and is not modified afterwards.
unsafe { (*self.root_job_handle.get()).as_ref().unwrap().as_ref() }
}
/// Returns the memory pressure event for the given `kind`.
pub fn get_mem_pressure_event(&self, kind: u32) -> Option<fbl::RefPtr<EventDispatcher>> {
self.memory_watchdog.get_mem_pressure_event(kind)
}
/// Returns a reference to the memory watchdog for this executor.
pub fn get_memory_watchdog(&self) -> &MemoryWatchdog {
&self.memory_watchdog
}
/// Start watching the root job, taking a system-level action (such as restart) if
/// all its children are removed.
///
/// This must be called after the root job has at least one child process or child job.
pub fn start_root_job_observer(&self) {
// SAFETY: `start_root_job_observer` is called once during boot after `init`, and is the
// only place that accesses `root_job_observer`. `root_job` and `root_job_handle` are not
// modified after `init`.
unsafe {
assert!((*self.root_job_observer.get()).is_none());
debug_assert!((*self.root_job.get()).is_some());
let root_job = (*self.root_job.get()).as_ref().unwrap().clone();
let root_job_handle = (*self.root_job_handle.get()).as_ref().map(|h| h.as_ref());
let Ok(observer) = RootJobObserver::new(root_job, root_job_handle) else {
panic!("root-job: failed to allocate observer\n");
};
*self.root_job_observer.get() = Some(observer);
}
// Initialize the memory watchdog.
let self_ptr = NonNull::from(self);
// SAFETY: `self_ptr` points to `self`, which outlives `self.memory_watchdog`.
unsafe {
self.memory_watchdog.init(self_ptr);
}
}
}
/// Initializes `executor`.
///
/// # Safety
///
/// `executor` must point to a valid `Executor`, and `rust_executor_init` must only be called once
/// before any other methods on `executor`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_executor_init(executor: *mut Executor) {
// SAFETY: `executor` points to a valid `Executor`.
let executor = unsafe { &*executor };
executor.init();
}
/// Starts the root job observer and initializes the memory watchdog on `executor`.
///
/// # Safety
///
/// `executor` must point to a valid `Executor` that has been initialized via `rust_executor_init`
/// and will remain valid for the lifetime of the memory watchdog, and this function must only be
/// called once.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_executor_start_root_job_observer(executor: *mut Executor) {
// SAFETY: `executor` points to a valid `Executor`.
let executor = unsafe { &*executor };
executor.start_root_job_observer();
}