use core::{fmt, hash, marker::PhantomData};
use raw::KernelBase;
use super::{
cfg, raw, raw_cfg, ActivateTaskError, Cfg, GetCurrentTaskError, GetTaskPriorityError,
InterruptTaskError, SetTaskPriorityError, UnparkError, UnparkExactError,
};
use crate::{
closure::{Closure, IntoClosureConst},
utils::{Init, PhantomInvariant},
};
define_object! {
#[doc = common_doc_owned_handle!()]
#[doc = svgbobdoc::transform!(
/// ```svgbob
/// .-------.
/// .--------------->| Ready |<--------------.
/// | '-------' |
/// | dispatch | ^ |
/// | | | |
/// | release | | | activate
/// .---------. | | .---------.
/// | Waiting | | | | Dormant |
/// '---------' | | '---------'
/// ^ | | ^
/// | | | |
/// | v | preempt |
/// | wait .---------. |
/// '---------------| Running |--------------'
/// '---------' exit
/// ```
)]
#[doc = include_str!("../common.md")]
pub struct Task<System: _>(System::RawTaskId);
#[doc = include_str!("../common.md")]
pub struct TaskRef<System: raw::KernelBase>(_);
pub type StaticTask<System>;
pub trait TaskHandle {}
pub trait TaskMethods {}
}
impl<System: raw::KernelBase> StaticTask<System> {
pub const fn define() -> TaskDefiner<System> {
TaskDefiner::new()
}
}
#[doc = include_str!("../common.md")]
pub struct LocalTask<System: raw::KernelBase>(System::RawTaskId, PhantomData<*const ()>);
unsafe impl<System: raw::KernelBase> Sync for LocalTask<System> {}
unsafe impl<System: raw::KernelBase> const TaskHandle for LocalTask<System> {
type System = System;
#[inline]
unsafe fn from_id(id: System::RawTaskId) -> Self {
Self(id, PhantomData)
}
#[inline]
fn id(&self) -> System::RawTaskId {
self.0
}
#[inline]
fn borrow(&self) -> TaskRef<'_, Self::System> {
TaskRef(self.0, PhantomData)
}
}
impl<System: raw::KernelBase, T: TaskHandle<System = System>> PartialEq<T> for LocalTask<System> {
#[inline]
fn eq(&self, other: &T) -> bool {
self.0 == other.id()
}
}
impl<System: raw::KernelBase> Eq for LocalTask<System> {}
impl<System: raw::KernelBase> hash::Hash for LocalTask<System> {
#[inline]
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher,
{
self.borrow().hash(state)
}
}
impl<System: raw::KernelBase> fmt::Debug for LocalTask<System> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.borrow().fmt(f)
}
}
impl<System: raw::KernelBase> Clone for LocalTask<System> {
#[inline]
fn clone(&self) -> Self {
Self(self.0, self.1)
}
}
impl<System: raw::KernelBase> Copy for LocalTask<System> {}
impl<System: raw::KernelBase> LocalTask<System> {
#[inline]
pub fn current() -> Result<Self, GetCurrentTaskError> {
System::raw_task_current().map(|id| unsafe { Self::from_id(id) })
}
}
#[doc = include_str!("../common.md")]
pub trait TaskMethods: TaskHandle {
#[inline]
fn activate(&self) -> Result<(), ActivateTaskError> {
unsafe { <Self::System as KernelBase>::raw_task_activate(self.id()) }
}
#[inline]
fn interrupt(&self) -> Result<(), InterruptTaskError> {
unsafe { <Self::System as KernelBase>::raw_task_interrupt(self.id()) }
}
#[inline]
fn unpark(&self) -> Result<(), UnparkError> {
match self.unpark_exact() {
Ok(()) | Err(UnparkExactError::QueueOverflow) => Ok(()),
Err(UnparkExactError::BadContext) => Err(UnparkError::BadContext),
Err(UnparkExactError::NoAccess) => Err(UnparkError::NoAccess),
Err(UnparkExactError::BadObjectState) => Err(UnparkError::BadObjectState),
}
}
#[inline]
fn unpark_exact(&self) -> Result<(), UnparkExactError> {
unsafe { <Self::System as KernelBase>::raw_task_unpark_exact(self.id()) }
}
#[inline]
fn set_priority(&self, priority: usize) -> Result<(), SetTaskPriorityError>
where
Self::System: raw::KernelTaskSetPriority,
{
unsafe {
<Self::System as raw::KernelTaskSetPriority>::raw_task_set_priority(self.id(), priority)
}
}
#[inline]
fn priority(&self) -> Result<usize, GetTaskPriorityError> {
unsafe { <Self::System as raw::KernelBase>::raw_task_priority(self.id()) }
}
#[inline]
fn effective_priority(&self) -> Result<usize, GetTaskPriorityError> {
unsafe { <Self::System as raw::KernelBase>::raw_task_effective_priority(self.id()) }
}
}
impl<T: TaskHandle> TaskMethods for T {}
#[must_use = "must call `finish()` to complete registration"]
pub struct TaskDefiner<System> {
_phantom: PhantomInvariant<System>,
start: Option<Closure>,
stack_size: Option<usize>,
priority: Option<usize>,
active: bool,
}
impl<System: raw::KernelBase> TaskDefiner<System> {
const fn new() -> Self {
Self {
_phantom: Init::INIT,
start: None,
stack_size: None,
priority: None,
active: false,
}
}
pub const fn start<C: ~const IntoClosureConst>(self, start: C) -> Self {
Self {
start: Some(start.into_closure_const()),
..self
}
}
pub const fn stack_size(self, stack_size: usize) -> Self {
assert!(
self.stack_size.is_none(),
"the task's stack is already specified"
);
Self {
stack_size: Some(stack_size),
..self
}
}
pub const fn priority(self, priority: usize) -> Self {
Self {
priority: Some(priority),
..self
}
}
pub const fn active(self, active: bool) -> Self {
Self { active, ..self }
}
pub const fn finish<C: ~const raw_cfg::CfgTask<System = System>>(
self,
cfg: &mut Cfg<C>,
) -> StaticTask<System> {
let id = cfg.raw().task_define(
raw_cfg::TaskDescriptor {
phantom: Init::INIT,
start: self
.start
.expect("`start` (task entry point) is not specified"),
active: self.active,
priority: self
.priority
.expect("`priority` (task entry point) is not specified"),
stack_size: self.stack_size,
},
(),
);
unsafe { TaskRef::from_id(id) }
}
}
pub struct StackHunk<System: cfg::KernelStatic>(super::Hunk<System>);
impl<System: cfg::KernelStatic> StackHunk<System> {
pub const unsafe fn new(hunk: super::Hunk<System>) -> Self {
Self(hunk)
}
#[inline]
pub const fn hunk(self) -> super::Hunk<System> {
self.0
}
}
impl<System: cfg::KernelStatic> Clone for StackHunk<System> {
#[inline]
fn clone(&self) -> Self {
Self(self.0)
}
}
impl<System: cfg::KernelStatic> Copy for StackHunk<System> {}