Skip to content

Commit 117b76f

Browse files
committed
Merge branch '✨-task-set-priority' into 🦆
2 parents 99ccb67 + ea05c5b commit 117b76f

File tree

15 files changed

+501
-60
lines changed

15 files changed

+501
-60
lines changed

src/constance/src/kernel/cfg.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,16 +210,21 @@ macro_rules! array_item_from_fn {
210210
$static_or_const:tt $out:ident: [$ty:ty; _] = (0..$len:expr).map(|$var:ident| $map:expr);
211211
)*) => {$(
212212
$static_or_const $out: [$ty; { $len }] = {
213-
let mut values = [$crate::prelude::Init::INIT; { $len }];
213+
use $crate::{core::mem::MaybeUninit, utils::mem};
214+
let mut values: [MaybeUninit<$ty>; { $len }] = mem::uninit_array();
214215
let mut i = 0;
215216
while i < $len {
216-
values[i] = {
217+
values[i] = MaybeUninit::<$ty>::new({
217218
let $var = i;
218219
$map
219-
};
220+
});
220221
i += 1;
221222
}
222-
values
223+
224+
// Safety: The memory layout of `[MaybeUninit<$ty>; $len]` is
225+
// identical to `[$ty; $len]`. We initialized all elements, so it's
226+
// safe to reinterpret that range as `[$ty; $len]`.
227+
unsafe { mem::transmute(values) }
223228
};
224229
)*};
225230
}

src/constance/src/kernel/cfg/task.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,8 @@ impl<System: Port> CfgBuilderTask<System> {
179179
task::TaskCb {
180180
port_task_state: System::PORT_TASK_STATE_INIT,
181181
attr,
182-
priority: if self.priority < System::NUM_TASK_PRIORITY_LEVELS {
183-
System::TASK_PRIORITY_LEVELS[self.priority]
184-
} else {
185-
panic!("task's `priority` must be less than `num_task_priority_levels`");
186-
},
182+
// `self.priority` has already been checked by `to_attr`
183+
priority: CpuLockCell::new(System::TASK_PRIORITY_LEVELS[self.priority]),
187184
st: CpuLockCell::new(if self.active {
188185
task::TaskSt::PendingActivation
189186
} else {
@@ -200,6 +197,11 @@ impl<System: Port> CfgBuilderTask<System> {
200197
entry_point: self.start,
201198
entry_param: self.param,
202199
stack: self.stack,
200+
priority: if self.priority < System::NUM_TASK_PRIORITY_LEVELS {
201+
System::TASK_PRIORITY_LEVELS[self.priority]
202+
} else {
203+
panic!("task's `priority` must be less than `num_task_priority_levels`");
204+
},
203205
}
204206
}
205207
}

src/constance/src/kernel/error.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,23 @@ define_error! {
292292
}
293293
}
294294

295+
define_error! {
296+
mod set_task_priority_error {}
297+
/// Error type for [`Task::set_priority`].
298+
///
299+
/// [`Task::set_priority`]: super::Task::set_priority
300+
pub enum SetTaskPriorityError: BadContextError, BadIdError {
301+
/// The task ID is out of range.
302+
BadId,
303+
/// CPU Lock is active.
304+
BadContext,
305+
/// The priority is out of range.
306+
BadParam,
307+
/// The task is in the Dormant state.
308+
BadObjectState,
309+
}
310+
}
311+
295312
define_error! {
296313
mod exit_task_error {}
297314
/// Error type for [`Kernel::exit_task`].

src/constance/src/kernel/task.rs

Lines changed: 114 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
//! Tasks
2-
use core::{cell::UnsafeCell, fmt, hash, marker::PhantomData, mem, sync::atomic::Ordering};
2+
use core::{
3+
cell::UnsafeCell, convert::TryFrom, fmt, hash, marker::PhantomData, mem, sync::atomic::Ordering,
4+
};
35
use num_traits::ToPrimitive;
46

57
use super::{
68
hunk::Hunk, state, timeout, utils, wait, ActivateTaskError, BadIdError, ExitTaskError,
79
GetCurrentTaskError, Id, InterruptTaskError, Kernel, KernelCfg1, ParkError, ParkTimeoutError,
8-
Port, PortThreading, SleepError, UnparkError, UnparkExactError, WaitTimeoutError,
10+
Port, PortThreading, SetTaskPriorityError, SleepError, UnparkError, UnparkExactError,
11+
WaitTimeoutError,
912
};
1013
use crate::{
1114
time::Duration,
@@ -218,6 +221,27 @@ impl<System: Kernel> Task<System> {
218221
let task_cb = self.task_cb()?;
219222
unpark_exact(lock, task_cb)
220223
}
224+
225+
/// Set the task's priority.
226+
///
227+
/// Tasks with lower priority values execute first. The priority is reset to
228+
/// the initial value specified by [`CfgTaskBuilder::priority`] upon
229+
/// activation.
230+
///
231+
/// [`CfgTaskBuilder::priority`]: crate::kernel::cfg::CfgTaskBuilder::priority
232+
///
233+
/// The value must be in range `0..`[`num_task_priority_levels`]. Otherwise,
234+
/// this method will return [`SetTaskPriorityError::BadParam`].
235+
///
236+
/// The task shouldn't be in the Dormant state. Otherwise, this method will
237+
/// return [`SetTaskPriorityError::BadObjectState`].
238+
///
239+
/// [`num_task_priority_levels`]: crate::kernel::cfg::CfgBuilder::num_task_priority_levels
240+
pub fn set_priority(self, priority: usize) -> Result<(), SetTaskPriorityError> {
241+
let lock = utils::lock_cpu::<System>()?;
242+
let task_cb = self.task_cb()?;
243+
set_task_priority(lock, task_cb, priority)
244+
}
221245
}
222246

223247
/// [`Hunk`] for a task stack.
@@ -288,9 +312,9 @@ pub struct TaskCb<
288312
pub port_task_state: PortTaskState,
289313

290314
/// The static properties of the task.
291-
pub attr: &'static TaskAttr<System>,
315+
pub attr: &'static TaskAttr<System, TaskPriority>,
292316

293-
pub priority: TaskPriority,
317+
pub(super) priority: utils::CpuLockCell<System, TaskPriority>,
294318

295319
pub(super) st: utils::CpuLockCell<System, TaskSt>,
296320

@@ -309,20 +333,6 @@ pub struct TaskCb<
309333
pub(super) park_token: utils::CpuLockCell<System, bool>,
310334
}
311335

312-
impl<System: Port, PortTaskState: Init + 'static, TaskPriority: Init + 'static> Init
313-
for TaskCb<System, PortTaskState, TaskPriority>
314-
{
315-
const INIT: Self = Self {
316-
port_task_state: Init::INIT,
317-
attr: &TaskAttr::INIT,
318-
priority: Init::INIT,
319-
st: Init::INIT,
320-
link: Init::INIT,
321-
wait: Init::INIT,
322-
park_token: Init::INIT,
323-
};
324-
}
325-
326336
impl<System: Kernel, PortTaskState: fmt::Debug + 'static, TaskPriority: fmt::Debug + 'static>
327337
fmt::Debug for TaskCb<System, PortTaskState, TaskPriority>
328338
{
@@ -336,7 +346,7 @@ impl<System: Kernel, PortTaskState: fmt::Debug + 'static, TaskPriority: fmt::Deb
336346
}
337347

338348
/// The static properties of a task.
339-
pub struct TaskAttr<System> {
349+
pub struct TaskAttr<System, TaskPriority: 'static = <System as KernelCfg1>::TaskPriority> {
340350
/// The entry point of the task.
341351
///
342352
/// # Safety
@@ -353,22 +363,17 @@ pub struct TaskAttr<System> {
353363
// this is blocked by <https://github.com/rust-lang/const-eval/issues/11>
354364
/// The hunk representing the stack region for the task.
355365
pub stack: StackHunk<System>,
356-
}
357366

358-
impl<System> Init for TaskAttr<System> {
359-
const INIT: Self = Self {
360-
entry_point: |_| {},
361-
entry_param: 0,
362-
stack: StackHunk::INIT,
363-
};
367+
pub priority: TaskPriority,
364368
}
365369

366-
impl<System: Kernel> fmt::Debug for TaskAttr<System> {
370+
impl<System: Kernel, TaskPriority: fmt::Debug> fmt::Debug for TaskAttr<System, TaskPriority> {
367371
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
368372
f.debug_struct("TaskAttr")
369373
.field("entry_point", &self.entry_point)
370374
.field("entry_param", &self.entry_param)
371375
.field("stack", &self.stack)
376+
.field("priority", &self.priority)
372377
.finish()
373378
}
374379
}
@@ -505,6 +510,9 @@ fn activate<System: Kernel>(
505510
// Safety: CPU Lock active, the task is in the Dormant state
506511
unsafe { System::initialize_task_state(task_cb) };
507512

513+
// Reset the task priority
514+
task_cb.priority.replace(&mut *lock, task_cb.attr.priority);
515+
508516
// Safety: The previous state is Dormant, and we just initialized the task
509517
// state, so this is safe
510518
unsafe { make_ready(lock.borrow_mut(), task_cb) };
@@ -527,7 +535,7 @@ pub(super) unsafe fn make_ready<System: Kernel>(
527535
task_cb.st.replace(&mut *lock, TaskSt::Ready);
528536

529537
// Insert the task to a ready queue
530-
let pri = task_cb.priority.to_usize().unwrap();
538+
let pri = task_cb.priority.read(&*lock).to_usize().unwrap();
531539
list_accessor!(<System>::state().task_ready_queue[pri], lock.borrow_mut())
532540
.push_back(Ident(task_cb));
533541

@@ -555,7 +563,7 @@ pub(super) fn unlock_cpu_and_check_preemption<System: Kernel>(lock: utils::CpuLo
555563
}
556564

557565
let prev_task_priority = if let Some(running_task) = System::state().running_task() {
558-
running_task.priority.to_usize().unwrap()
566+
running_task.priority.read(&*lock).to_usize().unwrap()
559567
} else {
560568
usize::MAX
561569
};
@@ -595,7 +603,7 @@ pub(super) fn choose_next_running_task<System: Kernel>(
595603
let prev_running_task = System::state().running_task();
596604
let prev_task_priority = if let Some(running_task) = prev_running_task {
597605
if *running_task.st.read(&*lock) == TaskSt::Running {
598-
running_task.priority.to_usize().unwrap()
606+
running_task.priority.read(&*lock).to_usize().unwrap()
599607
} else {
600608
usize::MAX
601609
}
@@ -795,3 +803,79 @@ pub(super) fn put_current_task_on_sleep_timeout<System: Kernel>(
795803
Err(WaitTimeoutError::Timeout) => Ok(()),
796804
}
797805
}
806+
807+
/// Implements [`Task::set_priority`].
808+
fn set_task_priority<System: Kernel>(
809+
mut lock: utils::CpuLockGuard<System>,
810+
task_cb: &'static TaskCb<System>,
811+
priority: usize,
812+
) -> Result<(), SetTaskPriorityError> {
813+
// Validate the given priority
814+
if priority >= System::NUM_TASK_PRIORITY_LEVELS {
815+
return Err(SetTaskPriorityError::BadParam);
816+
}
817+
let priority_internal =
818+
System::TaskPriority::try_from(priority).unwrap_or_else(|_| unreachable!());
819+
820+
let st = *task_cb.st.read(&*lock);
821+
822+
if st == TaskSt::Dormant {
823+
return Err(SetTaskPriorityError::BadObjectState);
824+
}
825+
826+
// Assign the new priority
827+
let old_priority = task_cb
828+
.priority
829+
.replace(&mut *lock, priority_internal)
830+
.to_usize()
831+
.unwrap();
832+
833+
if old_priority == priority {
834+
return Ok(());
835+
}
836+
837+
match st {
838+
TaskSt::Ready => {
839+
// Move the task between ready queues
840+
let old_pri_empty = {
841+
let mut accessor = list_accessor!(
842+
<System>::state().task_ready_queue[old_priority],
843+
lock.borrow_mut()
844+
);
845+
accessor.remove(Ident(task_cb));
846+
accessor.is_empty()
847+
};
848+
849+
list_accessor!(
850+
<System>::state().task_ready_queue[priority],
851+
lock.borrow_mut()
852+
)
853+
.push_back(Ident(task_cb));
854+
855+
// Update `task_ready_bitmap` accordingly
856+
// (This code assumes `priority != old_priority`.)
857+
let task_ready_bitmap = System::state().task_ready_bitmap.write(&mut *lock);
858+
task_ready_bitmap.set(priority);
859+
if old_pri_empty {
860+
task_ready_bitmap.clear(old_priority);
861+
}
862+
}
863+
TaskSt::Running => {}
864+
TaskSt::Waiting => {
865+
// Reposition the task in a wait queue if the task is currently waiting
866+
wait::reorder_wait_of_task(lock.borrow_mut(), task_cb);
867+
}
868+
TaskSt::Dormant | TaskSt::PendingActivation => unreachable!(),
869+
}
870+
871+
if let TaskSt::Running | TaskSt::Ready = st {
872+
// - If `st == TaskSt::Running`, `task_cb` is the currently running
873+
// task. If the priority was lowered, it could be preempted by
874+
// a task in the Ready state.
875+
// - If `st == TaskSt::Ready` and the priority was raised, it could
876+
// preempt the currently running task.
877+
unlock_cpu_and_check_preemption(lock);
878+
}
879+
880+
Ok(())
881+
}

0 commit comments

Comments
 (0)