#[cfg(feature = "priority_boost")]
use core::sync::atomic::{AtomicBool, Ordering};
use core::{fmt, marker::PhantomData, mem::forget, num::NonZeroUsize, ops::Range};
use crate::{
time::{Duration, Time},
utils::{binary_heap::VecLike, BinUInteger, Init},
};
#[macro_use]
pub mod cfg;
mod error;
mod event_group;
mod hunk;
mod interrupt;
mod mutex;
mod semaphore;
mod startup;
mod state;
mod task;
mod timeout;
mod timer;
mod utils;
mod wait;
pub use self::{
error::*, event_group::*, hunk::*, interrupt::*, mutex::*, semaphore::*, startup::*, task::*,
timeout::*, timer::*, wait::*,
};
pub type Id = NonZeroUsize;
#[doc(include = "./common.md")]
pub trait Kernel: Port + KernelCfg2 + Sized + 'static {
type DebugPrinter: fmt::Debug + Send + Sync;
fn debug() -> Self::DebugPrinter;
fn acquire_cpu_lock() -> Result<(), CpuLockError>;
unsafe fn release_cpu_lock() -> Result<(), CpuLockError>;
fn has_cpu_lock() -> bool;
#[cfg(feature = "priority_boost")]
#[doc(cfg(feature = "priority_boost"))]
fn boost_priority() -> Result<(), BoostPriorityError>;
unsafe fn unboost_priority() -> Result<(), BoostPriorityError>;
fn is_priority_boost_active() -> bool;
#[cfg(feature = "system_time")]
#[doc(cfg(feature = "system_time"))]
fn time() -> Result<Time, TimeError>;
fn set_time(time: Time) -> Result<(), TimeError>;
#[cfg_attr(doc, svgbobdoc::transform)]
fn adjust_time(delta: Duration) -> Result<(), AdjustTimeError>;
unsafe fn exit_task() -> Result<!, ExitTaskError>;
fn park() -> Result<(), ParkError>;
fn park_timeout(timeout: Duration) -> Result<(), ParkTimeoutError>;
fn sleep(duration: Duration) -> Result<(), SleepError>;
}
impl<T: Port + KernelCfg2 + 'static> Kernel for T {
#[inline]
fn acquire_cpu_lock() -> Result<(), CpuLockError> {
if unsafe { Self::try_enter_cpu_lock() } {
Ok(())
} else {
Err(CpuLockError::BadContext)
}
}
#[inline]
unsafe fn release_cpu_lock() -> Result<(), CpuLockError> {
if !Self::is_cpu_lock_active() {
Err(CpuLockError::BadContext)
} else {
unsafe { Self::leave_cpu_lock() };
Ok(())
}
}
#[inline]
fn has_cpu_lock() -> bool {
Self::is_cpu_lock_active()
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
#[cfg(feature = "priority_boost")]
fn boost_priority() -> Result<(), BoostPriorityError> {
state::boost_priority::<Self>()
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
unsafe fn unboost_priority() -> Result<(), BoostPriorityError> {
state::unboost_priority::<Self>()
}
#[inline]
#[cfg(feature = "priority_boost")]
fn is_priority_boost_active() -> bool {
Self::state().priority_boost.load(Ordering::Relaxed)
}
#[inline]
#[cfg(not(feature = "priority_boost"))]
fn is_priority_boost_active() -> bool {
false
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
#[cfg(feature = "system_time")]
fn time() -> Result<Time, TimeError> {
timeout::system_time::<Self>()
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn set_time(time: Time) -> Result<(), TimeError> {
timeout::set_system_time::<Self>(time)
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn adjust_time(delta: Duration) -> Result<(), AdjustTimeError> {
timeout::adjust_system_and_event_time::<Self>(delta)
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
unsafe fn exit_task() -> Result<!, ExitTaskError> {
unsafe { exit_current_task::<Self>() }
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn park() -> Result<(), ParkError> {
task::park_current_task::<Self>()
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn park_timeout(timeout: Duration) -> Result<(), ParkTimeoutError> {
task::park_current_task_timeout::<Self>(timeout)
}
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
fn sleep(timeout: Duration) -> Result<(), SleepError> {
task::put_current_task_on_sleep_timeout::<Self>(timeout)
}
type DebugPrinter = KernelDebugPrinter<Self>;
#[inline]
fn debug() -> Self::DebugPrinter {
KernelDebugPrinter(PhantomData)
}
}
pub struct KernelDebugPrinter<T>(PhantomData<T>);
impl<T: Kernel> 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()
}
}
pub unsafe trait KernelCfg1: Sized + Send + Sync + 'static {
const NUM_TASK_PRIORITY_LEVELS: usize;
type TaskPriority: BinUInteger;
#[doc(hidden)]
type TaskReadyQueue: readyqueue::Queue<Self>;
const TASK_PRIORITY_LEVELS: &'static [Self::TaskPriority];
}
#[doc(include = "./common.md")]
#[allow(clippy::missing_safety_doc)]
pub unsafe trait PortThreading: KernelCfg1 {
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;
}
#[doc(include = "./common.md")]
#[allow(clippy::missing_safety_doc)]
pub unsafe trait PortInterrupts: KernelCfg1 {
#[allow(clippy::reversed_empty_ranges)] const MANAGED_INTERRUPT_PRIORITY_RANGE: Range<InterruptPriority> = 0..0;
const MANAGED_INTERRUPT_LINES: &'static [InterruptNum] = &[];
unsafe fn set_interrupt_line_priority(
_line: InterruptNum,
_priority: InterruptPriority,
) -> Result<(), SetInterruptLinePriorityError> {
Err(SetInterruptLinePriorityError::NotSupported)
}
unsafe fn enable_interrupt_line(_line: InterruptNum) -> Result<(), EnableInterruptLineError> {
Err(EnableInterruptLineError::NotSupported)
}
unsafe fn disable_interrupt_line(_line: InterruptNum) -> Result<(), EnableInterruptLineError> {
Err(EnableInterruptLineError::NotSupported)
}
unsafe fn pend_interrupt_line(_line: InterruptNum) -> Result<(), PendInterruptLineError> {
Err(PendInterruptLineError::NotSupported)
}
unsafe fn clear_interrupt_line(_line: InterruptNum) -> Result<(), ClearInterruptLineError> {
Err(ClearInterruptLineError::NotSupported)
}
unsafe fn is_interrupt_line_pending(
_line: InterruptNum,
) -> Result<bool, QueryInterruptLineError> {
Err(QueryInterruptLineError::NotSupported)
}
}
#[doc(include = "./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<System: Kernel> PortToKernel for System {
unsafe fn boot() -> ! {
let mut lock = unsafe { utils::assume_cpu_lock::<Self>() };
for cb in Self::task_cb_pool() {
task::init_task(lock.borrow_mut(), cb);
}
System::state().timeout.init(lock.borrow_mut());
for cb in Self::timer_cb_pool() {
timer::init_timer(lock.borrow_mut(), cb);
}
unsafe {
System::INTERRUPT_ATTR.init(lock.borrow_mut());
}
for hook in Self::STARTUP_HOOKS {
unsafe { (hook.start)(hook.param) };
}
forget(lock);
unsafe {
Self::dispatch_first_task();
}
}
#[inline]
unsafe fn choose_running_task() {
let mut lock = unsafe { utils::assume_cpu_lock::<Self>() };
task::choose_next_running_task(lock.borrow_mut());
forget(lock);
}
unsafe fn timer_tick() {
timeout::handle_tick::<Self>();
}
}
pub unsafe trait KernelCfg2: Port + Sized {
#[doc(hiddden)]
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_HOOKS: &'static [StartupHookAttr];
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<
System: KernelCfg2,
PortTaskState: 'static = <System as PortThreading>::PortTaskState,
TaskReadyQueue: 'static = <System as KernelCfg1>::TaskReadyQueue,
TaskPriority: 'static = <System as KernelCfg1>::TaskPriority,
TimeoutHeap: 'static = <System as KernelCfg2>::TimeoutHeap,
> {
running_task:
utils::CpuLockCell<System, Option<&'static TaskCb<System, PortTaskState, TaskPriority>>>,
task_ready_queue: TaskReadyQueue,
#[cfg(feature = "priority_boost")]
priority_boost: AtomicBool,
timeout: timeout::TimeoutGlobals<System, TimeoutHeap>,
}
impl<
System: KernelCfg2,
PortTaskState: 'static,
TaskReadyQueue: 'static + Init,
TaskPriority: 'static,
TimeoutHeap: 'static + Init,
> Init for State<System, PortTaskState, TaskReadyQueue, TaskPriority, TimeoutHeap>
{
const INIT: Self = Self {
running_task: utils::CpuLockCell::new(None),
task_ready_queue: Init::INIT,
#[cfg(feature = "priority_boost")]
priority_boost: AtomicBool::new(false),
timeout: Init::INIT,
};
}
impl<
System: Kernel,
PortTaskState: 'static + fmt::Debug,
TaskReadyQueue: 'static + fmt::Debug,
TaskPriority: 'static + fmt::Debug,
TimeoutHeap: 'static + fmt::Debug,
> fmt::Debug for State<System, 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<System: KernelCfg2> State<System> {
#[inline]
fn running_task(
&self,
lock: utils::CpuLockGuardBorrowMut<System>,
) -> Option<&'static TaskCb<System>> {
*self.running_task.read(&*lock)
}
#[inline]
pub fn running_task_ptr(&self) -> *mut Option<&'static TaskCb<System>> {
self.running_task.as_ptr()
}
}