#![feature(const_maybe_uninit_array_assume_init)]
#![feature(const_maybe_uninit_uninit_array)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(const_slice_from_raw_parts_mut)]
#![feature(maybe_uninit_array_assume_init)]
#![feature(maybe_uninit_uninit_array)]
#![feature(const_precise_live_drops)]
#![feature(const_raw_ptr_comparison)]
#![feature(cfg_target_has_atomic)] #![feature(exhaustive_patterns)] #![feature(generic_const_exprs)]
#![feature(const_refs_to_cell)]
#![feature(maybe_uninit_slice)]
#![feature(const_slice_index)]
#![feature(const_option_ext)]
#![feature(const_trait_impl)]
#![feature(const_ptr_write)]
#![feature(core_intrinsics)]
#![feature(specialization)]
#![feature(assert_matches)]
#![feature(const_mut_refs)]
#![feature(const_ptr_read)]
#![feature(const_convert)]
#![feature(const_option)]
#![feature(const_deref)]
#![feature(const_heap)]
#![feature(const_swap)]
#![feature(never_type)] #![feature(decl_macro)]
#![feature(pin_macro)]
#![feature(doc_cfg)] #![deny(unsafe_op_in_unsafe_fn)]
#![cfg_attr(
feature = "doc",
doc(html_logo_url = "https://r3-os.github.io/r3/logo-small.svg")
)]
#![doc = include_str!("./lib.md")]
#![doc = include_str!("./common.md")]
#![doc = include!("../doc/traits.rs")] #![cfg_attr(
feature = "_full",
doc = r#"<style type="text/css">.disabled-feature-warning { display: none; }</style>"#
)]
#![cfg_attr(not(test), no_std)]
#[doc(hidden)]
pub extern crate core;
#[doc(hidden)]
pub extern crate arrayvec;
#[doc(hidden)]
pub extern crate r3_core_ks as r3_core;
#[cfg(doc)]
#[doc = include_str!("../CHANGELOG.md")]
pub mod _changelog_ {}
pub mod utils;
#[cfg(feature = "priority_boost")]
use core::sync::atomic::{AtomicBool, Ordering};
use core::{fmt, marker::PhantomData, mem::forget, num::NonZeroUsize, ops::Range};
use r3_core::{
kernel::{
cfg::{DelegateKernelStatic, KernelStatic},
raw,
},
time::{Duration, Time},
utils::Init,
};
use crate::utils::{binary_heap::VecLike, BinUInteger};
#[macro_use]
pub mod cfg;
mod error;
mod event_group;
mod interrupt;
mod klock;
mod mutex;
mod semaphore;
mod state;
mod task;
mod timeout;
mod timer;
mod wait;
pub use {event_group::*, interrupt::*, mutex::*, semaphore::*, task::*, timeout::*, timer::*};
pub type Id = NonZeroUsize;
pub struct System<Traits>(PhantomData<Traits>);
impl<Traits> Clone for System<Traits> {
fn clone(&self) -> Self {
*self
}
}
impl<Traits> Copy for System<Traits> {}
impl<Traits> core::fmt::Debug for System<Traits> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("System")
}
}
pub type Cfg<'c, Traits> = r3_core::kernel::Cfg<'c, cfg::CfgBuilder<Traits>>;
pub trait KernelTraits: Port + KernelCfg2 + KernelStatic<System<Self>> + 'static {}
impl<Traits: Port + KernelCfg2 + KernelStatic<System<Self>> + 'static> KernelTraits for Traits {}
impl<Traits: KernelStatic<System<Traits>>> DelegateKernelStatic<System<Traits>> for System<Traits> {
type Target = Traits;
}
unsafe impl<Traits: KernelTraits> raw::KernelBase for System<Traits> {
const RAW_SUPPORTED_QUEUE_ORDERS: &'static [Option<raw::QueueOrderKind>] = &[
Some(raw::QueueOrderKind::Fifo),
Some(raw::QueueOrderKind::TaskPriority),
];
#[inline]
fn raw_acquire_cpu_lock() -> Result<(), r3_core::kernel::CpuLockError> {
if unsafe { Traits::try_enter_cpu_lock() } {
Ok(())
} else {
Err(r3_core::kernel::CpuLockError::BadContext)
}
}
#[inline]
unsafe fn raw_release_cpu_lock() -> Result<(), r3_core::kernel::CpuLockError> {
if !Traits::is_cpu_lock_active() {
Err(r3_core::kernel::CpuLockError::BadContext)
} else {
unsafe { Traits::leave_cpu_lock() };
Ok(())
}
}
#[inline]
fn raw_has_cpu_lock() -> bool {
Traits::is_cpu_lock_active()
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
unsafe fn raw_unboost_priority() -> Result<(), r3_core::kernel::BoostPriorityError> {
state::unboost_priority::<Traits>()
}
#[inline]
#[cfg(feature = "priority_boost")]
fn raw_is_priority_boost_active() -> bool {
Traits::state().priority_boost.load(Ordering::Relaxed)
}
#[inline]
#[cfg(not(feature = "priority_boost"))]
fn raw_is_priority_boost_active() -> bool {
false
}
#[inline]
fn raw_is_task_context() -> bool {
Traits::is_task_context()
}
#[inline]
fn raw_is_interrupt_context() -> bool {
Traits::is_interrupt_context()
}
#[inline]
fn raw_is_boot_complete() -> bool {
Traits::is_scheduler_active()
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn raw_set_time(time: Time) -> Result<(), r3_core::kernel::TimeError> {
timeout::set_system_time::<Traits>(time)
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
unsafe fn raw_exit_task() -> Result<!, r3_core::kernel::ExitTaskError> {
unsafe { task::exit_current_task::<Traits>() }
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn raw_park() -> Result<(), r3_core::kernel::ParkError> {
task::park_current_task::<Traits>()
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn raw_park_timeout(timeout: Duration) -> Result<(), r3_core::kernel::ParkTimeoutError> {
task::park_current_task_timeout::<Traits>(timeout)
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn raw_sleep(timeout: Duration) -> Result<(), r3_core::kernel::SleepError> {
task::put_current_task_on_sleep_timeout::<Traits>(timeout)
}
type RawDebugPrinter = KernelDebugPrinter<Traits>;
#[inline]
fn raw_debug() -> Self::RawDebugPrinter {
KernelDebugPrinter(PhantomData)
}
type RawTaskId = task::TaskId;
#[inline]
fn raw_task_current() -> Result<Self::RawTaskId, r3_core::kernel::GetCurrentTaskError> {
Self::task_current()
}
#[inline]
unsafe fn raw_task_activate(
this: Self::RawTaskId,
) -> Result<(), r3_core::kernel::ActivateTaskError> {
Self::task_activate(this)
}
#[inline]
unsafe fn raw_task_interrupt(
this: Self::RawTaskId,
) -> Result<(), r3_core::kernel::InterruptTaskError> {
Self::task_interrupt(this)
}
#[inline]
unsafe fn raw_task_unpark_exact(
this: Self::RawTaskId,
) -> Result<(), r3_core::kernel::UnparkExactError> {
Self::task_unpark_exact(this)
}
#[inline]
unsafe fn raw_task_priority(
this: Self::RawTaskId,
) -> Result<usize, r3_core::kernel::GetTaskPriorityError> {
Self::task_priority(this)
}
#[inline]
unsafe fn raw_task_effective_priority(
this: Self::RawTaskId,
) -> Result<usize, r3_core::kernel::GetTaskPriorityError> {
Self::task_effective_priority(this)
}
}
unsafe impl<Traits: KernelTraits> raw::KernelTaskSetPriority for System<Traits> {
#[inline]
unsafe fn raw_task_set_priority(
this: Self::RawTaskId,
priority: usize,
) -> Result<(), r3_core::kernel::SetTaskPriorityError> {
Self::task_set_priority(this, priority)
}
}
#[cfg(feature = "priority_boost")]
#[doc(cfg(feature = "priority_boost"))]
unsafe impl<Traits: KernelTraits> raw::KernelBoostPriority for System<Traits> {
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn raw_boost_priority() -> Result<(), r3_core::kernel::BoostPriorityError> {
state::boost_priority::<Traits>()
}
}
#[cfg(feature = "system_time")]
#[doc(cfg(feature = "system_time"))]
unsafe impl<Traits: KernelTraits> raw::KernelTime for System<Traits> {
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn raw_time() -> Result<Time, r3_core::kernel::TimeError> {
timeout::system_time::<Traits>()
}
}
unsafe impl<Traits: KernelTraits> raw::KernelAdjustTime for System<Traits> {
const RAW_TIME_USER_HEADROOM: Duration = TIME_USER_HEADROOM;
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn raw_adjust_time(delta: Duration) -> Result<(), r3_core::kernel::AdjustTimeError> {
timeout::adjust_system_and_event_time::<Traits>(delta)
}
}
pub struct KernelDebugPrinter<T>(PhantomData<T>);
impl<T: KernelTraits> fmt::Debug for KernelDebugPrinter<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
struct PoolPrinter<'a, T>(&'a [T]);
impl<T: fmt::Debug> fmt::Debug for PoolPrinter<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_map().entries(self.0.iter().enumerate()).finish()
}
}
f.debug_struct("Kernel")
.field("state", T::state())
.field("task_cb_pool", &PoolPrinter(T::task_cb_pool()))
.field(
"event_group_cb_pool",
&PoolPrinter(T::event_group_cb_pool()),
)
.field("mutex_cb_pool", &PoolPrinter(T::mutex_cb_pool()))
.field("semaphore_cb_pool", &PoolPrinter(T::semaphore_cb_pool()))
.field("timer_cb_pool", &PoolPrinter(T::timer_cb_pool()))
.finish()
}
}
#[const_trait]
pub unsafe trait KernelCfg1: Sized + Send + Sync + 'static {
const NUM_TASK_PRIORITY_LEVELS: usize;
type TaskPriority: BinUInteger;
#[doc(hidden)]
type TaskReadyQueue: readyqueue::Queue<Self>;
fn to_task_priority(i: usize) -> Option<Self::TaskPriority>;
}
#[doc = include_str!("./common.md")]
#[allow(clippy::missing_safety_doc)]
pub unsafe trait PortThreading: KernelCfg1 + KernelStatic<System<Self>> {
type PortTaskState: Send + Sync + Init + fmt::Debug + 'static;
#[allow(clippy::declare_interior_mutable_const)] const PORT_TASK_STATE_INIT: Self::PortTaskState;
const STACK_DEFAULT_SIZE: usize = 1024;
const STACK_ALIGN: usize = core::mem::size_of::<usize>();
unsafe fn dispatch_first_task() -> !;
unsafe fn yield_cpu();
unsafe fn exit_and_dispatch(task: &'static task::TaskCb<Self>) -> !;
unsafe fn enter_cpu_lock();
unsafe fn leave_cpu_lock();
unsafe fn try_enter_cpu_lock() -> bool {
if Self::is_cpu_lock_active() {
false
} else {
unsafe { Self::enter_cpu_lock() };
true
}
}
unsafe fn initialize_task_state(task: &'static task::TaskCb<Self>);
fn is_cpu_lock_active() -> bool;
fn is_task_context() -> bool;
fn is_interrupt_context() -> bool;
fn is_scheduler_active() -> bool;
}
#[doc = include_str!("./common.md")]
#[allow(clippy::missing_safety_doc)]
pub unsafe trait PortInterrupts: KernelCfg1 {
#[allow(clippy::reversed_empty_ranges)] const MANAGED_INTERRUPT_PRIORITY_RANGE: Range<raw::InterruptPriority> = 0..0;
const MANAGED_INTERRUPT_LINES: &'static [raw::InterruptNum] = &[];
unsafe fn set_interrupt_line_priority(
_line: raw::InterruptNum,
_priority: raw::InterruptPriority,
) -> Result<(), r3_core::kernel::SetInterruptLinePriorityError> {
Err(r3_core::kernel::SetInterruptLinePriorityError::NotSupported)
}
unsafe fn enable_interrupt_line(
_line: raw::InterruptNum,
) -> Result<(), r3_core::kernel::EnableInterruptLineError> {
Err(r3_core::kernel::EnableInterruptLineError::NotSupported)
}
unsafe fn disable_interrupt_line(
_line: raw::InterruptNum,
) -> Result<(), r3_core::kernel::EnableInterruptLineError> {
Err(r3_core::kernel::EnableInterruptLineError::NotSupported)
}
unsafe fn pend_interrupt_line(
_line: raw::InterruptNum,
) -> Result<(), r3_core::kernel::PendInterruptLineError> {
Err(r3_core::kernel::PendInterruptLineError::NotSupported)
}
unsafe fn clear_interrupt_line(
_line: raw::InterruptNum,
) -> Result<(), r3_core::kernel::ClearInterruptLineError> {
Err(r3_core::kernel::ClearInterruptLineError::NotSupported)
}
unsafe fn is_interrupt_line_pending(
_line: raw::InterruptNum,
) -> Result<bool, r3_core::kernel::QueryInterruptLineError> {
Err(r3_core::kernel::QueryInterruptLineError::NotSupported)
}
}
#[doc = include_str!("./common.md")]
#[allow(clippy::missing_safety_doc)]
pub trait PortTimer {
const MAX_TICK_COUNT: UTicks;
const MAX_TIMEOUT: UTicks;
unsafe fn tick_count() -> UTicks;
unsafe fn pend_tick_after(tick_count_delta: UTicks) {
let _ = tick_count_delta;
}
unsafe fn pend_tick() {
unsafe { Self::pend_tick_after(1) };
}
}
pub type UTicks = u32;
pub trait Port: PortThreading + PortInterrupts + PortTimer {}
impl<T: PortThreading + PortInterrupts + PortTimer> Port for T {}
#[allow(clippy::missing_safety_doc)]
pub trait PortToKernel {
unsafe fn boot() -> !;
unsafe fn choose_running_task();
unsafe fn timer_tick();
}
impl<Traits: KernelTraits> PortToKernel for Traits {
#[inline(always)]
unsafe fn boot() -> ! {
let mut lock = unsafe { klock::assume_cpu_lock::<Traits>() };
for cb in Traits::task_cb_pool() {
task::init_task(lock.borrow_mut(), cb);
}
Traits::state().timeout.init(lock.borrow_mut());
for cb in Traits::timer_cb_pool() {
timer::init_timer(lock.borrow_mut(), cb);
}
unsafe {
Traits::INTERRUPT_ATTR.init(lock.borrow_mut());
}
unsafe { (Traits::STARTUP_HOOK)() };
forget(lock);
unsafe {
Traits::dispatch_first_task();
}
}
#[inline(always)]
unsafe fn choose_running_task() {
let mut lock = unsafe { klock::assume_cpu_lock::<Traits>() };
task::choose_next_running_task(lock.borrow_mut());
forget(lock);
}
#[inline(always)]
unsafe fn timer_tick() {
timeout::handle_tick::<Traits>();
}
}
pub unsafe trait KernelCfg2: Port + Sized + KernelStatic<System<Self>> {
#[doc(hidden)]
type TimeoutHeap: VecLike<Element = timeout::TimeoutRef<Self>> + Init + fmt::Debug + 'static;
const INTERRUPT_HANDLERS: &'static cfg::InterruptHandlerTable;
#[doc(hidden)]
const INTERRUPT_ATTR: InterruptAttr<Self>;
#[doc(hidden)]
const STARTUP_HOOK: unsafe fn();
fn state() -> &'static State<Self>;
#[doc(hidden)]
fn hunk_pool_ptr() -> *mut u8;
#[doc(hidden)]
fn task_cb_pool() -> &'static [TaskCb<Self>];
#[doc(hidden)]
#[inline(always)]
fn get_task_cb(i: usize) -> Option<&'static TaskCb<Self>> {
Self::task_cb_pool().get(i)
}
#[doc(hidden)]
fn event_group_cb_pool() -> &'static [EventGroupCb<Self>];
#[doc(hidden)]
#[inline(always)]
fn get_event_group_cb(i: usize) -> Option<&'static EventGroupCb<Self>> {
Self::event_group_cb_pool().get(i)
}
#[doc(hidden)]
fn mutex_cb_pool() -> &'static [MutexCb<Self>];
#[doc(hidden)]
#[inline(always)]
fn get_mutex_cb(i: usize) -> Option<&'static MutexCb<Self>> {
Self::mutex_cb_pool().get(i)
}
#[doc(hidden)]
fn semaphore_cb_pool() -> &'static [SemaphoreCb<Self>];
#[doc(hidden)]
#[inline(always)]
fn get_semaphore_cb(i: usize) -> Option<&'static SemaphoreCb<Self>> {
Self::semaphore_cb_pool().get(i)
}
#[doc(hidden)]
fn timer_cb_pool() -> &'static [TimerCb<Self>];
#[doc(hidden)]
#[inline(always)]
fn get_timer_cb(i: usize) -> Option<&'static TimerCb<Self>> {
Self::timer_cb_pool().get(i)
}
}
pub struct State<
Traits: KernelCfg2,
PortTaskState: 'static = <Traits as PortThreading>::PortTaskState,
TaskReadyQueue: 'static = <Traits as KernelCfg1>::TaskReadyQueue,
TaskPriority: 'static = <Traits as KernelCfg1>::TaskPriority,
TimeoutHeap: 'static = <Traits as KernelCfg2>::TimeoutHeap,
> {
running_task:
klock::CpuLockCell<Traits, Option<&'static TaskCb<Traits, PortTaskState, TaskPriority>>>,
task_ready_queue: TaskReadyQueue,
#[cfg(feature = "priority_boost")]
priority_boost: AtomicBool,
timeout: timeout::TimeoutGlobals<Traits, TimeoutHeap>,
}
impl<
Traits: KernelCfg2,
PortTaskState: 'static,
TaskReadyQueue: 'static + Init,
TaskPriority: 'static,
TimeoutHeap: 'static + Init,
> Init for State<Traits, PortTaskState, TaskReadyQueue, TaskPriority, TimeoutHeap>
{
const INIT: Self = Self {
running_task: klock::CpuLockCell::new(None),
task_ready_queue: Init::INIT,
#[cfg(feature = "priority_boost")]
priority_boost: AtomicBool::new(false),
timeout: Init::INIT,
};
}
impl<
Traits: KernelTraits,
PortTaskState: 'static + fmt::Debug,
TaskReadyQueue: 'static + fmt::Debug,
TaskPriority: 'static + fmt::Debug,
TimeoutHeap: 'static + fmt::Debug,
> fmt::Debug for State<Traits, PortTaskState, TaskReadyQueue, TaskPriority, TimeoutHeap>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("State")
.field("running_task", &self.running_task.get_and_debug_fmt())
.field("task_ready_queue", &self.task_ready_queue)
.field(
"priority_boost",
match () {
#[cfg(feature = "priority_boost")]
() => &self.priority_boost,
#[cfg(not(feature = "priority_boost"))]
() => &(),
},
)
.field("timeout", &self.timeout)
.finish()
}
}
impl<Traits: KernelCfg2> State<Traits> {
#[inline]
fn running_task(
&self,
lock: klock::CpuLockTokenRefMut<Traits>,
) -> Option<&'static TaskCb<Traits>> {
*self.running_task.read(&*lock)
}
#[inline]
pub fn running_task_ptr(&self) -> *mut Option<&'static TaskCb<Traits>> {
self.running_task.as_ptr()
}
}
#[inline]
unsafe fn bad_id<Traits: KernelCfg2>() -> error::NoAccessError {
let _ = error::NoAccessError::NoAccess;
if cfg!(debug_assertion) {
panic!("invalid kernel object ID");
} else {
unsafe { core::hint::unreachable_unchecked() }
}
}