The original kernel of [R3-OS][].
- Traditional uniprocessor tickless real-time kernel with preemptive scheduling
- Implements a software-based scheduler supporting a customizable number of task priorities (up to 2¹⁵ levels on a 32-bit target, though the implementation is heavily optimized for a smaller number of priorities) and an unlimited number of tasks.
- Provides a scalable kernel timing mechanism with a logarithmic time complexity. This implementation is robust against a large interrupt processing delay.
- The kernel is split into a target-independent portion and a target-specific portion. The target-specific portion (called *a port*) is provided as a separate crate. An application **combines them using the trait system**.
[R3-OS]: https://crates.io/crates/r3
<!-- Display a "some Cargo features are disabled" warning in the documentation so that the user can know some items are missing for that reason. But we don't want this message to be displayed when someone is viewing `lib.md` directly, so the actual message is rendered by CSS. -->
<div class="admonition-follows"></div>
<blockquote class="disabled-feature-warning"><p><span></span><code></code></p></blockquote>
<div class="toc-header"></div>
- [Configuring the Kernel](#configuring-the-kernel)
- [Kernel Trait Type](#kernel-trait-type)
- [Trait Mechanics](#trait-mechanics)
- [Implementation-Defined Behaviors](#implementation-defined-behaviors)
- [Cargo Features](#cargo-features)
- [Modules](#modules) <!-- this section is generated by rustdoc -->
- [Macros](#macros) <!-- this section is generated by rustdoc -->
- [Structs](#structs) <!-- this section is generated by rustdoc -->
- [Constants](#constants) <!-- this section is generated by rustdoc -->
- [Traits](#traits) <!-- this section is generated by rustdoc -->
- [Type Definitions](#types) <!-- this section is generated by rustdoc -->
# Configuring the Kernel
## Kernel Trait Type
The R3 original kernel utilizes Rust's trait system to allow system designers to combine necessary components of the kernel. Components are represented by traits implemented on an application-specific **kernel trait type**, often named `SystemTraits` by convention. The kernel trait type is then used as a parameter of [`r3_kernel::System`][]`<Traits>` to form a concrete [system type][].
<div class="admonition-follows"></div>
> **Rationale:** "Trait" is an allusion to the type trait classes such as `std::iterator_traits` from the C++ standard library. You could also say that it's named so because you implement various traits on it to configure the kernel, though.
Application code uses the following macros to build a kernel trait type in a modular way:
- A port-provided macro like **`r3_xxx_port::use_port!`** (named in this way by convention) instantiates port-specfific items.
- **[`r3_kernel::build!`][]** instantiates the kernel and kernel-private static data based on the kernel configuration supplied in the form of a **[configuration function][]**.
<!-- FIXME: To work around <https://github.com/rust-lang/cargo/issues/4242>, implement <https://github.com/rust-lang/futures-rs/pull/2305> and make the following code block doc-testable -->
```rust,ignore
type System = r3_kernel::System<SystemTraits>;
r3_port_std::use_port!(unsafe struct SystemTraits);
struct Objects { /* ... */ }
const fn configure_app(_: &mut r3_kernel::Cfg<SystemTraits>) -> Objects
{ /* ... */ }
const COTTAGE: Objects = r3_kernel::build!(System, configure_app => Objects);
```
[`r3_kernel::build!`]: crate::build
[`r3_kernel::System`]: crate::System
[system type]: r3_core#system-type
[configuration function]: r3_core#static-configuration
## Trait Mechanics
The macros presented in the previous section generate many trait implementations interconnected under a complex relationship to the end of providing all necessary components. This section provides a detailed account of how this is implemented. **An application developer is usually not required to understand this.**
The following diagram outlines the trait relationship around a kernel trait type.
- The arrows between traits represent a super-sub relationship. It's not possible to create a circular dependency among them. Associated types can only be referenced in one direction.
- The `impl`s in the same crate as the implemented traits are blanket `impl`s.
- The arrows between `impl`s represent trait bounds on `Self` (for blanket `impl`s) or assumed `impl`s (for the other `impl`s). It's not possible to create a circular dependency fully comprised of blanket `impl`s, but otherwise it's possible to create one.
<span class="center">![traits]</span>
### `use_port!` → System Type
The composition process revolves around a kernel trait type. The first thing to do is to define one. It could be defined by application code, but instead it's defined by `use_port!` purely for convenience. A kernel trait type is named `SystemTrait` by convention.
```rust,ignore
r3_xxx_port::use_port!(unsafe struct SystemTrait);
// ----- The above macro invocation expands to: -----
struct SystemTrait;
/* ⋮ */
```
### `use_port!` → `impl Port`
The first important role of `use_port!` is to implement the trait [`Port`] on the kernel trait type. `Port` describes the properties of the target hardware and provides target-dependent low-level functions such as a context switcher. `use_port!` can define `static` items to store internal state data (this would be inconvenient and messy without a macro).
`Port` is actually a group of several supertraits (such as [`PortThreading`]), each of which can be implemented in a separate location.
```rust,ignore
r3_xxx_port::use_port!(unsafe struct SystemTraits);
// ----- The above macro invocation also produces: -----
/* ⋮ */
unsafe impl r3_kernel::PortThreading for SystemTraits { /* ... */ }
unsafe impl r3_kernel::PortInterrupts for SystemTraits { /* ... */ }
unsafe impl r3_kernel::PortTimer for SystemTraits { /* ... */ }
/* ⋮ */
// `Port` gets implemented automatically when
// all required supertraits are implemented.
```
The job of `use_port!` doesn't end here, but before we move on, we must first explain what `build!` does.
[`Port`]: crate::Port
[`PortThreading`]: crate::PortThreading
### `build!` → `impl KernelCfgN`
`build!` assembles a database of statically defined kernel objects using a supplied [configuration function][]. Using this database, it does things such as determining the optimal data type to represent all allowed task priority values and defining `static` items to store kernel-private data structures such as task control blocks. The result is attached to a supplied kernel trait type by implementing [`KernelCfg1`] and [`KernelCfg2`] on it.
```rust,ignore
static COTTAGE: Objects =
r3_kernel::build!(SystemTraits, configure_app => Objects);
// ----- The above macro invocation produces (simplified for brevity): -----
static COTTAGE: Objects = {
use r3_kernel::TaskCb;
const CFG: /* ... */ = {
let mut raw_cfg = r3_kernel::cfg::CfgBuilder::new();
let mut cfg = r3_core::kernel::cfg::Cfg::new(&mut raw_cfg);
configure_app(&mut cfg);
raw_cfg
};
static TASK_CB_POOL: [TaskCb<SystemTraits>; _] = /* ... */;
// Things needed by both of `Port` and `KernelCfg2` should live in
// `KernelCfg1` because `Port` cannot refer to an associated item defined
// by `KernelCfg2`.
unsafe impl r3_kernel::KernelCfg1 for SystemTraits {
type TaskPriority = /* ... */;
}
// Things dependent on data types defined by `Port` should live in
// `KernelCfg2`.
unsafe impl r3_kernel::KernelCfg2 for SystemTraits {
fn task_cb_pool() -> &'static [TaskCb<SystemTraits>] {
&TASK_CB_POOL
}
/* ... */
}
// Make the generated object IDs available to the application
configure_app(...)
};
```
[configuration function]: r3_core#static-configuration
[`KernelCfg1`]: crate::KernelCfg1
[`KernelCfg2`]: crate::KernelCfg2
### `impl KernelTraits`
The traits introduced so far are enough to instantiate the target-independent portion of the RTOS kernel. To reflect this, [`KernelTraits`] and [`PortToKernel`] are automatically implemented on the kernel trait type by a blanket `impl`.
```rust,ignore
impl<System: Port + KernelCfg1 + KernelCfg2> KernelTraits for System { /* ... */ }
impl<System: KernelTraits> PortToKernel for System { /* ... */ }
```
[`KernelTraits`]: crate::KernelTraits
[`PortToKernel`]: crate::PortToKernel
### `use_port!` → Entry Points
The remaining task of `use_port!` is to generate entry points to the kernel. The most important one is for booting the kernel. The other ones are [interrupt handlers].
```rust,ignore
r3_xxx_port::use_port!(unsafe struct SystemTraits);
// ----- The above macro invocation lastly produces: -----
/* ⋮ */
fn main() {
<SystemTraits as r3_kernel::PortToKernel>::boot();
}
```
[interrupt handlers]: r3_core#interrupt-handling-framework
# Implementation-Defined Behaviors
- **[`QueueOrder`]**: This kernel supports `Fifo` and `TaskPriority`. Unsupported values are treated as `TaskPriority`.
- **[`MutexProtocol`]**: This kernel supports `None` and `Ceiling(_)`. Unsupported values are treated as `None`.
- **[`ResultCode::NoAccess`]**: Not supported. This kernel causes an undefined behavior (including a potential panic) when an invalid ID is given.
[`QueueOrder`]: r3_core::kernel::QueueOrder
[`MutexProtocol`]: r3_core::kernel::MutexProtocol
[`ResultCode::NoAccess`]: r3_core::kernel::ResultCode::NoAccess
# Cargo Features
- **`inline_syscall`**: Allows (but does not force) inlining for all application-facing methods. Enabling this feature might lower the latency of system calls but there are the following downsides: (1) The decision of inlining is driven by the compiler's built-in heuristics, which takes many factors into consideration. Therefore, the performance improvement (or deterioration) varies unpredictably depending on the global structure of your application and the compiler version used, making it harder to design the system to meet real-time requirements. (2) Inlining increases the code working set size and can make the code run even slower. This is especially likely to happen on an execute-in-place (XIP) system with low-speed code memory such as an SPI flash.
## Kernel Features
Enabling the following features might affect the kernel's runtime performance and memory usage whether or not they are actually in use.
- **`priority_boost`**: Enables [Priority Boost][] ([`raw::KernelBoostPriority`][]).
- **`system_time`**: Enables the tracking of a global system time ([`raw::KernelTime`][]).
[Priority Boost]: r3_core::kernel::Kernel::boost_priority
[`raw::KernelBoostPriority`]: r3_core::kernel::raw::KernelBoostPriority
[`raw::KernelTime`]: r3_core::kernel::raw::KernelTime