use core::{
cell::UnsafeCell,
ffi::CStr,
mem::zeroed,
panic::{RefUnwindSafe, UnwindSafe},
ptr::null_mut,
str,
};
use crate::{
bindings::{
rt_context_init, rt_syscall_pendable, rt_syscall_record, rt_task, rt_task_drop_privilege,
rt_task_exit, rt_task_init, rt_task_name, rt_task_sleep, rt_task_sleep_periodic,
rt_task_state, rt_task_yield,
},
list::list_init,
ptr_macros::{ptr_to_field, ptr_to_field_mut},
tick::Utick,
};
#[repr(transparent)]
pub struct Task {
pub(crate) task: UnsafeCell<rt_task>,
}
unsafe impl Send for Task {}
unsafe impl Sync for Task {}
impl UnwindSafe for Task {}
impl RefUnwindSafe for Task {}
#[inline]
pub fn yield_now() {
unsafe { rt_task_yield() }
}
#[inline]
pub fn sleep(ticks: Utick) {
unsafe { rt_task_sleep(ticks) }
}
#[inline]
pub fn sleep_periodic(last_wake_tick: &mut Utick, period: Utick) {
unsafe { rt_task_sleep_periodic(last_wake_tick, period) }
}
#[inline]
pub fn exit() -> ! {
unsafe { rt_task_exit() }
}
#[inline]
pub fn name() -> &'static str {
unsafe { str::from_utf8_unchecked(CStr::from_ptr(rt_task_name()).to_bytes()) }
}
#[inline]
pub fn drop_privilege() {
unsafe { rt_task_drop_privilege() }
}
impl Task {
#[must_use]
pub const unsafe fn init(this: *const Self, name: &'static CStr, priority: u32) -> Task {
let task = UnsafeCell::raw_get(ptr_to_field!(this, task));
Task {
task: UnsafeCell::new(rt_task {
list: list_init(ptr_to_field_mut!(task, list)),
sleep_list: list_init(ptr_to_field_mut!(task, sleep_list)),
ctx: null_mut(),
priority,
base_priority: priority,
state: rt_task_state::RT_TASK_STATE_READY,
wake_tick: 0,
#[cfg(feature = "task-mpu")]
mpu_config: unsafe { zeroed() },
blocker: unsafe { zeroed() },
syscall_return: unsafe { zeroed() },
mutex_list: list_init(ptr_to_field_mut!(task, mutex_list)),
pending_function_record: rt_syscall_record {
next: null_mut(),
args: unsafe { zeroed() },
syscall: rt_syscall_pendable::RT_SYSCALL_PENDABLE_FUNCTION,
pending: unsafe { zeroed() },
},
fn_: unsafe { zeroed() },
arg: 0,
stack: null_mut(),
stack_size: 0,
name: name.as_ptr(),
global_task_list: list_init(ptr_to_field_mut!(task, global_task_list)),
}),
}
}
pub fn ready(&'static self, f: extern "C" fn(), stack: *mut u8, stack_size: usize) {
let t = self.task.get();
let fnptr = f as usize;
unsafe {
(*t).ctx = rt_context_init(fnptr, 0, stack.cast(), stack_size);
(*t).fn_.uintptr = fnptr;
(*t).stack = stack.cast();
(*t).stack_size = stack_size;
rt_task_init(t);
}
}
}
#[macro_export]
macro_rules! task_name {
($fn: ident ()) => {
core::concat!(core::stringify!($fn), "\0")
};
($fn: ident $params: tt) => {
core::concat!(core::stringify!($fn), core::stringify!($params), "\0")
};
}
#[doc(hidden)]
#[macro_export]
#[cfg(feature = "task-mpu")]
macro_rules! mpu_config_init {
($fn: ident$(, $mpu_regions: expr)*) => { $crate::paste::paste! {
let stack_region = $crate::mpu::Region::from_stack(
&[< $fn:upper _TASK_STACK >]
);
$crate::mpu::task_mpu_config_init(
&[< $fn:upper _TASK >],
&[stack_region, $($mpu_regions),*],
);
}};
}
#[doc(hidden)]
#[macro_export]
#[cfg(not(feature = "task-mpu"))]
macro_rules! mpu_config_init {
($fn: ident$(, $mpu_regions: expr)*) => {};
}
#[doc(hidden)]
#[macro_export]
#[cfg(all(feature = "task-mpu", not(mpu_armv6m)))]
macro_rules! task_section {
($name: ident, $taskdef: item) => {
#[unsafe(link_section = stringify!(.priv_data.$name))]
$taskdef
};
}
#[doc(hidden)]
#[macro_export]
#[cfg(not(all(feature = "task-mpu", not(mpu_armv6m))))]
macro_rules! task_section {
($name: ident, $taskdef: item) => {
$taskdef
};
}
#[macro_export]
macro_rules! task {
($fn: ident $params: tt, $stack_size: expr, $priority: expr$(, $mpu_regions: expr)*) => {
const _: () = {
use core::{concat, stringify, ffi::CStr};
use $crate::{
cell::SyncUnsafeCell,
ctor,
mpu_config_init,
paste::paste,
stack::Stack,
task::Task,
task_name,
};
paste! {
$crate::task_section!(
[< $fn:upper _TASK >],
static [< $fn:upper _TASK >]: Task = {
let ptr = &raw const [< $fn:upper _TASK >];
let name_bytes = task_name!($fn $params).as_bytes();
let name = unsafe { CStr::from_bytes_with_nul_unchecked(name_bytes) };
let priority = $priority;
unsafe { Task::init(ptr, name, priority) }
};
);
#[cfg_attr(target_os = "none", unsafe(link_section = ".stack"))]
static [< $fn:upper _TASK_STACK >]: Stack<{$stack_size}> = Stack::new();
extern "C" fn [< $fn _task_fn >]() {
$fn $params
}
extern "C" fn [< $fn _task_init >]() {
mpu_config_init!($fn $(, $mpu_regions)*);
let ptr = SyncUnsafeCell::raw_get(&raw const [< $fn:upper _TASK_STACK >].buf);
[< $fn:upper _TASK >].ready([< $fn _task_fn >], ptr.cast(), $stack_size);
}
ctor!([< $fn:upper _TASK_INIT >], [< $fn _task_init >]);
}
};
};
($fn: ident, $stack_size: expr, $priority: expr) => {
rt::task!($fn(), $stack_size, $priority);
};
}