use crate::exec::process::ProcessInternal;
use crate::sched::event::Event;
use crate::stack::Stack;
use crate::time;
use bern_arch::arch::memory_protection::MemoryRegion;
use bern_arch::arch::Arch;
use bern_arch::memory_protection::{Access, Config, Permission, Type};
use bern_arch::IMemoryProtection;
use bern_conf::CONF;
use core::fmt::Debug;
use core::ptr::NonNull;
#[cfg(feature = "log-defmt")]
use defmt::Formatter;
#[cfg(feature = "_log_fmt")]
use core::fmt::Display;
pub trait RunnableTrait: 'static + FnMut() -> RunnableResult {}
pub type RunnableResult = ();
#[derive(Copy, Clone, PartialEq)]
#[repr(u8)]
pub enum Transition {
None,
Sleeping,
Blocked,
Resuming,
Terminating,
}
#[derive(PartialEq, PartialOrd, Debug, Copy, Clone)]
pub struct Priority(u8);
impl Priority {
const _HIGHEST: Priority = Priority(0);
const LOWEST: Priority = Priority(CONF.kernel.priorities - 2);
const IDLE: Priority = Priority(CONF.kernel.priorities - 1);
pub(crate) const MAX: Priority = Priority(u8::MAX);
pub const fn new(prio: u8) -> Self {
assert!(prio <= Priority::LOWEST.0);
Priority(prio)
}
pub fn is_idle(&self) -> bool {
self.raw() == Priority::IDLE.raw()
}
pub const fn idle() -> Self {
Priority::IDLE
}
pub fn is_interrupt_handler(self) -> bool {
self.raw() == 0
}
pub fn raw(&self) -> u8 {
self.0
}
}
impl Default for Priority {
fn default() -> Self {
Priority::LOWEST
}
}
impl From<Priority> for usize {
fn from(p: Priority) -> Self {
p.raw() as usize
}
}
impl From<Priority> for u8 {
fn from(p: Priority) -> Self {
p.raw()
}
}
pub struct Runnable {
id: u32,
process: &'static ProcessInternal,
transition: Transition,
runnable_ptr: *mut usize,
next_wut: u64,
stack: Stack,
priority: Priority,
blocking_event: Option<NonNull<Event>>,
memory_regions: [MemoryRegion; 3],
name: &'static str,
}
impl Runnable {
pub(crate) fn new(
process: &'static ProcessInternal,
runnable_ptr: *mut usize,
stack: Stack,
priority: Priority,
name: Option<&'static str>,
) -> Self {
let memory_regions = [
Arch::prepare_memory_region(
0,
Config {
addr: process.start_addr() as *const _,
memory: Type::SramInternal,
size: process.size(),
access: Access {
user: Permission::ReadWrite,
system: Permission::ReadWrite,
},
executable: false,
},
),
Arch::prepare_memory_region(
1,
Config {
addr: stack.bottom_ptr() as *const _,
memory: Type::SramInternal,
size: Arch::min_region_size(),
access: Access {
user: Permission::NoAccess,
system: Permission::NoAccess,
},
executable: false,
},
),
Arch::prepare_unused_region(2),
];
Runnable {
process,
transition: Transition::None,
runnable_ptr,
next_wut: 0,
stack,
priority,
blocking_event: None,
memory_regions,
id: 0,
name: name.unwrap_or("\0"),
}
}
pub(crate) fn runnable_ptr(&self) -> *const usize {
self.runnable_ptr
}
pub(crate) fn stack(&self) -> &Stack {
&self.stack
}
pub(crate) fn stack_mut(&mut self) -> &mut Stack {
&mut self.stack
}
pub(crate) fn next_wut(&self) -> u64 {
self.next_wut
}
pub(crate) fn sleep(&mut self, ms: u32) {
self.next_wut = time::tick_count() + u64::from(ms);
}
pub(crate) fn transition(&self) -> &Transition {
&self.transition
}
pub(crate) fn set_transition(&mut self, transition: Transition) {
self.transition = transition;
}
pub(crate) fn priority(&self) -> Priority {
self.priority
}
pub(crate) fn memory_regions(&self) -> &[MemoryRegion; 3] {
&self.memory_regions
}
pub(crate) fn blocking_event(&self) -> Option<NonNull<Event>> {
self.blocking_event
}
pub(crate) fn set_blocking_event(&mut self, event: NonNull<Event>) {
self.blocking_event = Some(event);
}
pub(crate) fn process(&self) -> &ProcessInternal {
self.process
}
pub(crate) fn id(&self) -> u32 {
self.id
}
pub(crate) fn set_id(&mut self, id: u32) {
self.id = id;
}
pub(crate) fn name(&self) -> &'static str {
self.name
}
}
pub(crate) fn entry(entry_fn: &mut &mut dyn FnMut() -> RunnableResult) {
(entry_fn)();
}
#[cfg(feature = "log-defmt")]
impl defmt::Format for Runnable {
fn format(&self, fmt: Formatter) {
defmt::write!(
fmt,
"None {:02} {:05}B/{:05}B ({:02}%)",
self.priority.0,
self.stack.usage().0,
self.stack.capacity().0,
(self.stack.usage().0 as f32 / self.stack.capacity().0 as f32 * 100f32) as u8,
)
}
}
#[cfg(feature = "_log_fmt")]
impl Display for Runnable {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"None {:02} {:05}B/{:05}B ({:02}%)",
self.priority.0,
self.stack.usage().0,
self.stack.capacity().0,
(self.stack.usage().0 as f32 / self.stack.capacity().0 as f32 * 100f32) as u8,
)
}
}