138 lines
4.4 KiB
Rust
138 lines
4.4 KiB
Rust
use core::{
|
|
cell::UnsafeCell,
|
|
ffi::{c_void, CStr},
|
|
marker::PhantomPinned,
|
|
mem::zeroed,
|
|
panic::{RefUnwindSafe, UnwindSafe},
|
|
ptr::null_mut,
|
|
str,
|
|
};
|
|
|
|
use crate::{
|
|
bindings::{
|
|
rt_context_init, rt_syscall_op, rt_syscall_pend, rt_syscall_push, rt_syscall_record,
|
|
rt_task, rt_task_drop_privilege, rt_task_exit, rt_task_name, rt_task_sleep,
|
|
rt_task_sleep_periodic, rt_task_state, rt_task_yield, RT_STACK_MIN,
|
|
},
|
|
list::list_init,
|
|
tick::Utick,
|
|
};
|
|
|
|
pub const STACK_MIN: usize = RT_STACK_MIN as usize;
|
|
|
|
pub struct Task {
|
|
t: UnsafeCell<rt_task>,
|
|
_pin_marker: PhantomPinned,
|
|
}
|
|
|
|
unsafe impl Send for Task {}
|
|
unsafe impl Sync for Task {}
|
|
impl UnwindSafe for Task {}
|
|
impl RefUnwindSafe for Task {}
|
|
|
|
pub fn yield_() {
|
|
unsafe { rt_task_yield() }
|
|
}
|
|
|
|
pub fn sleep(ticks: Utick) {
|
|
unsafe { rt_task_sleep(ticks) }
|
|
}
|
|
|
|
pub fn sleep_periodic(last_wake_tick: &mut Utick, period: Utick) {
|
|
unsafe { rt_task_sleep_periodic(last_wake_tick, period) }
|
|
}
|
|
|
|
pub fn exit() -> ! {
|
|
unsafe { rt_task_exit() }
|
|
}
|
|
|
|
pub fn name() -> &'static str {
|
|
unsafe { str::from_utf8_unchecked(CStr::from_ptr(rt_task_name()).to_bytes()) }
|
|
}
|
|
|
|
pub fn drop_privilege() {
|
|
unsafe { rt_task_drop_privilege() }
|
|
}
|
|
|
|
impl Task {
|
|
pub const fn init(task: &'static Task, name: &'static CStr, priority: u32) -> Task {
|
|
let t = unsafe { &*(task.t.get() as *const rt_task) };
|
|
Task {
|
|
t: UnsafeCell::new(rt_task {
|
|
list: list_init(&t.list),
|
|
sleep_list: list_init(&t.sleep_list),
|
|
ctx: null_mut(),
|
|
priority,
|
|
base_priority: priority,
|
|
state: rt_task_state::RT_TASK_STATE_INIT,
|
|
wake_tick: 0,
|
|
wait_list_head: null_mut(),
|
|
blocking_mutex: null_mut(),
|
|
timeout_ptr: unsafe { zeroed() },
|
|
mutex_list: list_init(&t.mutex_list),
|
|
name: name.as_ptr(),
|
|
}),
|
|
_pin_marker: PhantomPinned,
|
|
}
|
|
}
|
|
|
|
pub fn ready(
|
|
&mut self,
|
|
ready_record: &mut rt_syscall_record,
|
|
f: extern "C" fn(),
|
|
stack: &mut [u8],
|
|
) {
|
|
let t = self.t.get_mut();
|
|
unsafe {
|
|
t.ctx = rt_context_init(Some(f), stack.as_mut_ptr() as *mut c_void, stack.len());
|
|
ready_record.args.task_ready.task = t;
|
|
ready_record.op = rt_syscall_op::RT_SYSCALL_TASK_READY;
|
|
rt_syscall_push(ready_record);
|
|
rt_syscall_pend();
|
|
}
|
|
}
|
|
}
|
|
|
|
#[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")
|
|
};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! task {
|
|
($fn: ident $params: tt, $stack_size: expr, $priority: expr) => {
|
|
const _: () = {
|
|
$crate::paste::paste! {
|
|
static mut [< $fn:upper _TASK >]: rt::task::Task = rt::task::Task::init(
|
|
unsafe { &[< $fn:upper _TASK >] },
|
|
unsafe { core::ffi::CStr::from_bytes_with_nul_unchecked($crate::task_name!($fn $params).as_bytes()) },
|
|
$priority,
|
|
);
|
|
static mut [< $fn:upper _TASK_STACK >]: [u8; $stack_size] = [0u8; $stack_size];
|
|
extern fn [< $fn _c >]() {
|
|
$fn $params
|
|
}
|
|
/* Use a task ready syscall in the constructor rather than directly adding the task
|
|
* to the ready list because the ready list might not be initialized yet. If rust
|
|
* gains support for constructor priorities then this could be used instead. */
|
|
static mut [< $fn:upper _READY_RECORD >]: $crate::rt_syscall_record = unsafe { core::mem::zeroed() };
|
|
unsafe extern fn [< $fn _task_init >]() {
|
|
[< $fn:upper _TASK >].ready(&mut [< $fn:upper _READY_RECORD >], [< $fn _c >], [< $fn:upper _TASK_STACK >].as_mut_slice());
|
|
}
|
|
#[used]
|
|
#[cfg_attr(any(target_os = "none", target_os = "linux"), link_section = ".init_array")]
|
|
static [< $fn:upper _TASK_INIT >]: unsafe extern fn() = [< $fn _task_init >];
|
|
}
|
|
};
|
|
};
|
|
|
|
($fn: ident, $stack_size: expr, $priority: expr) => {
|
|
rt::task!($fn(), $stack_size, $priority);
|
|
};
|
|
}
|