Remove priority field from OSTD Task struct

This commit is contained in:
jellllly420 2024-09-14 15:32:21 +08:00 committed by Tate, Hongliang Tian
parent 0a36760f7a
commit 8927031426
18 changed files with 258 additions and 252 deletions

13
Cargo.lock generated
View File

@ -164,12 +164,9 @@ dependencies = [
"aster-time",
"aster-util",
"aster-virtio",
"atomic",
"atomic-integer-wrapper",
"bitflags 1.3.2",
"bitvec",
"bytemuck",
"bytemuck_derive",
"cfg-if",
"component",
"controlled",
@ -266,15 +263,6 @@ dependencies = [
"typeflags-util",
]
[[package]]
name = "atomic"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994"
dependencies = [
"bytemuck",
]
[[package]]
name = "atomic-integer-wrapper"
version = "0.1.0"
@ -1345,6 +1333,7 @@ dependencies = [
"cfg-if",
"defmt",
"heapless",
"log",
"managed",
]

View File

@ -55,9 +55,6 @@ rand = { version = "0.8.5", default-features = false, features = [
static_assertions = "1.1.0"
inherit-methods-macro = { git = "https://github.com/asterinas/inherit-methods-macro", rev = "98f7e3e" }
getset = "0.1.2"
atomic = "0.6"
bytemuck = "1.17.0"
bytemuck_derive = "1.7.1"
takeable = "0.2.2"
cfg-if = "1.0"

View File

@ -37,12 +37,13 @@ use ostd::{
arch::qemu::{exit_qemu, QemuExitCode},
boot,
cpu::PinCurrentCpu,
task::Priority,
};
use process::Process;
use sched::priority::PriorityRange;
use crate::{
prelude::*,
sched::priority::Priority,
thread::{
kernel_thread::{KernelThreadExt, ThreadOptions},
Thread,
@ -91,7 +92,10 @@ pub fn main() {
ostd::boot::smp::register_ap_entry(ap_init);
// Spawn the first kernel thread on BSP.
Thread::spawn_kernel_thread(ThreadOptions::new(init_thread).priority(Priority::lowest()));
Thread::spawn_kernel_thread(
ThreadOptions::new(init_thread)
.priority(Priority::new(PriorityRange::new(PriorityRange::MAX))),
);
// Spawning functions in the bootstrap context will not return.
unreachable!()
}
@ -126,7 +130,7 @@ fn ap_init() -> ! {
Thread::spawn_kernel_thread(
ThreadOptions::new(ap_idle_thread)
.cpu_affinity(cpu_id.into())
.priority(Priority::lowest()),
.priority(Priority::new(PriorityRange::new(PriorityRange::MAX))),
);
// Spawning functions in the bootstrap context will not return.
unreachable!()

View File

@ -4,10 +4,11 @@ use alloc::sync::Arc;
use core::time::Duration;
use log::trace;
use ostd::{arch::timer::Jiffies, task::Priority};
use ostd::arch::timer::Jiffies;
use super::{ext::IfaceEx, Iface, IFACES};
use crate::{
sched::priority::{Priority, PriorityRange},
thread::{
kernel_thread::{KernelThreadExt, ThreadOptions},
Thread,
@ -68,6 +69,7 @@ fn spawn_background_poll_thread(iface: Arc<Iface>) {
}
};
let options = ThreadOptions::new(task_fn).priority(Priority::high());
// FIXME: remove the use of real-time priority.
let options = ThreadOptions::new(task_fn).priority(Priority::new(PriorityRange::new(0)));
Thread::spawn_kernel_thread(options);
}

View File

@ -12,6 +12,7 @@ use crate::{
signal::{sig_mask::AtomicSigMask, sig_queues::SigQueues},
Credentials, Process,
},
sched::priority::Priority,
thread::{status::ThreadStatus, task, Thread, Tid},
time::{clocks::ProfClock, TimerManager},
};
@ -111,7 +112,13 @@ impl PosixThreadBuilder {
};
let status = ThreadStatus::Init;
let thread = Arc::new(Thread::new(weak_task.clone(), posix_thread, status));
let priority = Priority::default();
let thread = Arc::new(Thread::new(
weak_task.clone(),
posix_thread,
status,
priority,
));
thread_table::add_thread(tid, thread.clone());
task::create_new_user_task(user_space, thread)

View File

@ -13,7 +13,7 @@ use crate::{
signal::sig_disposition::SigDispositions,
Credentials,
},
sched::nice::Nice,
sched::priority::Nice,
};
pub struct ProcessBuilder<'a> {

View File

@ -20,7 +20,7 @@ use crate::{
device::tty::open_ntty_as_controlling_terminal,
fs::{file_table::FileTable, fs_resolver::FsResolver, utils::FileCreationMask},
prelude::*,
sched::nice::Nice,
sched::priority::{AtomicNice, Nice},
thread::Thread,
time::clocks::ProfClock,
vm::vmar::Vmar,
@ -34,7 +34,6 @@ mod terminal;
mod timer_manager;
use aster_rights::Full;
use atomic::Atomic;
use atomic_integer_wrapper::define_atomic_version_of_integer_like_type;
pub use builder::ProcessBuilder;
pub use job_control::JobControl;
@ -93,7 +92,7 @@ pub struct Process {
/// Scheduling priority nice value
/// According to POSIX.1, the nice value is a per-process attribute,
/// the threads in a process should share a nice value.
nice: Atomic<Nice>,
nice: AtomicNice,
// Signal
/// Sig dispositions
@ -223,7 +222,7 @@ impl Process {
parent_death_signal: AtomicSigNum::new_empty(),
exit_signal: AtomicSigNum::new_empty(),
resource_limits: Mutex::new(resource_limits),
nice: Atomic::new(nice),
nice: AtomicNice::new(nice),
timer_manager: PosixTimerManager::new(&prof_clock, process_ref),
prof_clock,
})
@ -329,7 +328,7 @@ impl Process {
&self.resource_limits
}
pub fn nice(&self) -> &Atomic<Nice> {
pub fn nice(&self) -> &AtomicNice {
&self.nice
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
pub mod nice;
pub mod priority;
mod priority_scheduler;
// There may be multiple scheduling policies in the system,

View File

@ -1,103 +0,0 @@
// SPDX-License-Identifier: MPL-2.0
use bytemuck_derive::NoUninit;
use crate::prelude::*;
/// The process scheduling nice value.
///
/// The nice value is an attribute that can be used to influence the
/// CPU scheduler to favor or disfavor a process in scheduling decisions.
///
/// It is a value in the range -20 to 19, with -20 being the highest priority
/// and 19 being the lowest priority. The smaller values give a process a higher
/// scheduling priority.
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, NoUninit)]
pub struct Nice {
value: i8,
}
impl Nice {
/// The minimum nice, whose value is -20.
pub const MIN: Self = Self { value: -20 };
/// The maximum nice, whose value is 19.
pub const MAX: Self = Self { value: 19 };
/// Creates a new `Nice` from the raw value.
///
/// Values given beyond the permissible range are automatically adjusted
/// to the nearest boundary value.
pub fn new(raw: i8) -> Self {
Self {
value: raw.clamp(Self::MIN.to_raw(), Self::MAX.to_raw()),
}
}
/// Converts to the raw value.
pub fn to_raw(self) -> i8 {
self.value
}
}
#[allow(clippy::derivable_impls)]
impl Default for Nice {
fn default() -> Self {
Self {
// The default nice value is 0
value: 0,
}
}
}
impl From<Priority> for Nice {
fn from(priority: Priority) -> Self {
Self {
value: 20 - priority.to_raw() as i8,
}
}
}
/// The process scheduling priority value.
///
/// It is a value in the range 1 (corresponding to a nice value of 19)
/// to 40 (corresponding to a nice value of -20), with 1 being the lowest priority
/// and 40 being the highest priority. The greater values give a process a higher
/// scheduling priority.
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, NoUninit)]
pub struct Priority {
value: u8,
}
impl Priority {
/// The minimum priority, whose value is 1.
pub const MIN: Self = Self { value: 1 };
/// The maximum priority, whose value is 40.
pub const MAX: Self = Self { value: 40 };
/// Creates a new `Priority` from the raw value.
///
/// Values given beyond the permissible range are automatically adjusted
/// to the nearest boundary value.
pub fn new(raw: u8) -> Self {
Self {
value: raw.clamp(Self::MIN.to_raw(), Self::MAX.to_raw()),
}
}
/// Converts to the raw value.
pub fn to_raw(self) -> u8 {
self.value
}
}
impl From<Nice> for Priority {
fn from(nice: Nice) -> Self {
Self {
value: (20 - nice.to_raw()) as u8,
}
}
}

View File

@ -0,0 +1,159 @@
// SPDX-License-Identifier: MPL-2.0
use core::sync::atomic::{AtomicI8, AtomicU8};
use atomic_integer_wrapper::define_atomic_version_of_integer_like_type;
/// The process scheduling nice value.
///
/// It is an integer in the range of [-20, 19]. Process with a smaller nice
/// value is more favorable in scheduling.
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Nice(NiceRange);
pub type NiceRange = RangedI8<-20, 19>;
define_atomic_version_of_integer_like_type!(Nice, try_from = true, {
#[derive(Debug)]
pub struct AtomicNice(AtomicI8);
});
impl Nice {
pub const fn new(range: NiceRange) -> Self {
Self(range)
}
pub fn range(&self) -> &NiceRange {
&self.0
}
pub fn range_mut(&mut self) -> &mut NiceRange {
&mut self.0
}
}
impl Default for Nice {
fn default() -> Self {
Self::new(NiceRange::new(0))
}
}
impl From<Nice> for i8 {
fn from(value: Nice) -> Self {
value.0.into()
}
}
impl TryFrom<i8> for Nice {
type Error = <NiceRange as TryFrom<i8>>::Error;
fn try_from(value: i8) -> Result<Self, Self::Error> {
let range = value.try_into()?;
Ok(Self::new(range))
}
}
/// The thread scheduling priority value.
///
/// It is an integer in the range of [0, 139]. Here we follow the Linux
/// priority mappings: the relation between [`Priority`] and [`Nice`] is
/// as such - prio = nice + 120 while the priority of [0, 100] are
/// reserved for real-time tasks.
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Priority(PriorityRange);
pub type PriorityRange = RangedU8<0, 139>;
define_atomic_version_of_integer_like_type!(Priority, try_from = true, {
#[derive(Debug)]
pub struct AtomicPriority(AtomicU8);
});
impl Priority {
pub const fn new(range: PriorityRange) -> Self {
Self(range)
}
pub fn range(&self) -> &PriorityRange {
&self.0
}
pub fn range_mut(&mut self) -> &mut PriorityRange {
&mut self.0
}
}
impl From<Nice> for Priority {
fn from(value: Nice) -> Self {
Self::new(PriorityRange::new(value.range().get() as u8 + 120))
}
}
impl Default for Priority {
fn default() -> Self {
Nice::default().into()
}
}
impl From<Priority> for u8 {
fn from(value: Priority) -> Self {
value.0.into()
}
}
impl TryFrom<u8> for Priority {
type Error = <PriorityRange as TryFrom<u8>>::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
let range = value.try_into()?;
Ok(Self::new(range))
}
}
macro_rules! define_ranged_integer {
($visibility: vis, $name: ident, $type: ty) => {
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
$visibility struct $name<const MIN: $type, const MAX: $type>($type);
impl<const MIN: $type, const MAX: $type> $name<MIN, MAX> {
$visibility const MIN: $type = MIN as $type;
$visibility const MAX: $type = MAX as $type;
$visibility const fn new(val: $type) -> Self {
assert!(val >= MIN && val <= MAX);
Self(val)
}
$visibility fn set(&mut self, val: $type) {
assert!(val >= MIN && val <= MAX);
self.0 = val;
}
$visibility fn get(self) -> $type {
self.0
}
}
impl<const MIN: $type, const MAX: $type> From<$name<MIN, MAX>> for $type {
fn from(value: $name<MIN, MAX>) -> Self {
value.0
}
}
impl<const MIN: $type, const MAX: $type> TryFrom<$type> for $name<MIN, MAX> {
type Error = &'static str;
fn try_from(value: $type) -> Result<Self, Self::Error> {
if value < Self::MIN || value > Self::MAX {
Err("Initialized with out-of-range value.")
} else {
Ok(Self(value))
}
}
}
};
}
define_ranged_integer!(pub, RangedI8, i8);
define_ranged_integer!(pub, RangedU8, u8);

View File

@ -4,12 +4,13 @@ use ostd::{
cpu::{num_cpus, CpuSet, PinCurrentCpu},
task::{
scheduler::{inject_scheduler, EnqueueFlags, LocalRunQueue, Scheduler, UpdateFlags},
AtomicCpuId, Priority, Task,
AtomicCpuId, Task,
},
trap::disable_local,
};
use crate::prelude::*;
use super::priority::{Priority, PriorityRange};
use crate::{prelude::*, thread::Thread};
pub fn init() {
let preempt_scheduler = Box::new(PreemptScheduler::default());
@ -244,13 +245,14 @@ impl Default for TimeSlice {
}
impl PreemptSchedInfo for Task {
type PRIORITY = Priority;
const REAL_TIME_TASK_PRIORITY: Priority = Priority::new(PriorityRange::new(100));
const LOWEST_TASK_PRIORITY: Priority = Priority::new(PriorityRange::new(PriorityRange::MAX));
const REAL_TIME_TASK_PRIORITY: Self::PRIORITY = Priority::new(100);
const LOWEST_TASK_PRIORITY: Self::PRIORITY = Priority::lowest();
fn priority(&self) -> Self::PRIORITY {
self.schedule_info().priority
fn priority(&self) -> Priority {
self.data()
.downcast_ref::<Arc<Thread>>()
.unwrap()
.priority()
}
fn cpu(&self) -> &AtomicCpuId {
@ -263,12 +265,10 @@ impl PreemptSchedInfo for Task {
}
trait PreemptSchedInfo {
type PRIORITY: Ord + PartialOrd + Eq + PartialEq;
const REAL_TIME_TASK_PRIORITY: Priority;
const LOWEST_TASK_PRIORITY: Priority;
const REAL_TIME_TASK_PRIORITY: Self::PRIORITY;
const LOWEST_TASK_PRIORITY: Self::PRIORITY;
fn priority(&self) -> Self::PRIORITY;
fn priority(&self) -> Priority;
fn cpu(&self) -> &AtomicCpuId;

View File

@ -6,14 +6,14 @@ use super::SyscallReturn;
use crate::{
prelude::*,
process::{posix_thread::PosixThreadExt, process_table, Pgid, Pid, Process, Uid},
sched::nice::Nice,
sched::priority::{Nice, NiceRange},
};
pub fn sys_set_priority(which: i32, who: u32, prio: i32, ctx: &Context) -> Result<SyscallReturn> {
let prio_target = PriorityTarget::new(which, who, ctx)?;
let new_nice = {
let norm_prio = prio.clamp(i8::MIN as i32, i8::MAX as i32) as i8;
Nice::new(norm_prio)
let nice_raw = prio.clamp(NiceRange::MIN as i32, NiceRange::MAX as i32) as i8;
Nice::new(NiceRange::new(nice_raw))
};
debug!(
@ -35,9 +35,9 @@ pub fn sys_get_priority(which: i32, who: u32, ctx: &Context) -> Result<SyscallRe
let processes = get_processes(prio_target)?;
let highest_prio = {
let mut nice = Nice::MAX;
let mut nice = NiceRange::MAX;
for process in processes.iter() {
let proc_nice = process.nice().load(Ordering::Relaxed);
let proc_nice = process.nice().load(Ordering::Relaxed).range().get();
// Returns the highest priority enjoyed by the processes
if proc_nice < nice {
nice = proc_nice;
@ -46,7 +46,7 @@ pub fn sys_get_priority(which: i32, who: u32, ctx: &Context) -> Result<SyscallRe
// The system call returns nice values translated to the range 40 to 1,
// since a negative return value would be interpreted as an error.
20 - nice.to_raw()
20 - nice
};
Ok(SyscallReturn::Return(highest_prio as _))

View File

@ -2,11 +2,11 @@
use ostd::{
cpu::CpuSet,
task::{Priority, Task, TaskOptions},
task::{Task, TaskOptions},
};
use super::{status::ThreadStatus, Thread};
use crate::prelude::*;
use crate::{prelude::*, sched::priority::Priority};
/// The inner data of a kernel thread
pub struct KernelThread;
@ -54,12 +54,17 @@ pub fn create_new_kernel_task(mut thread_options: ThreadOptions) -> Arc<Task> {
let thread = {
let kernel_thread = KernelThread;
let status = ThreadStatus::Init;
Arc::new(Thread::new(weak_task.clone(), kernel_thread, status))
let priority = thread_options.priority;
Arc::new(Thread::new(
weak_task.clone(),
kernel_thread,
status,
priority,
))
};
TaskOptions::new(thread_fn)
.data(thread)
.priority(thread_options.priority)
.cpu_affinity(thread_options.cpu_affinity)
.build()
.unwrap()
@ -81,7 +86,7 @@ impl ThreadOptions {
let cpu_affinity = CpuSet::new_full();
Self {
func: Some(Box::new(func)),
priority: Priority::normal(),
priority: Priority::default(),
cpu_affinity,
}
}

View File

@ -7,7 +7,10 @@ use core::sync::atomic::Ordering;
use ostd::task::Task;
use self::status::{AtomicThreadStatus, ThreadStatus};
use crate::prelude::*;
use crate::{
prelude::*,
sched::priority::{AtomicPriority, Priority},
};
pub mod exception;
pub mod kernel_thread;
@ -26,16 +29,25 @@ pub struct Thread {
data: Box<dyn Send + Sync + Any>,
// mutable part
/// Thread status
status: AtomicThreadStatus,
/// Thread priority
priority: AtomicPriority,
}
impl Thread {
/// Never call these function directly
pub fn new(task: Weak<Task>, data: impl Send + Sync + Any, status: ThreadStatus) -> Self {
pub fn new(
task: Weak<Task>,
data: impl Send + Sync + Any,
status: ThreadStatus,
priority: Priority,
) -> Self {
Thread {
task,
data: Box::new(data),
status: AtomicThreadStatus::new(status),
priority: AtomicPriority::new(priority),
}
}
@ -79,11 +91,26 @@ impl Thread {
self.status.load(Ordering::Acquire)
}
/// Updates the status with the `new` value.
/// Updates the status with the new value.
pub fn set_status(&self, new_status: ThreadStatus) {
self.status.store(new_status, Ordering::Release);
}
/// Returns the reference to the atomic priority.
pub fn atomic_priority(&self) -> &AtomicPriority {
&self.priority
}
/// Returns the current priority.
pub fn priority(&self) -> Priority {
self.priority.load(Ordering::Relaxed)
}
/// Updates the priority with the new value.
pub fn set_priority(&self, new_priority: Priority) {
self.priority.store(new_priority, Ordering::Relaxed)
}
pub fn yield_now() {
Task::yield_now()
}

View File

@ -2,14 +2,12 @@
#![allow(dead_code)]
use ostd::{
cpu::CpuSet,
task::{Priority, Task},
};
use ostd::{cpu::CpuSet, task::Task};
use super::worker_pool::WorkerPool;
use crate::{
prelude::*,
sched::priority::{Priority, PriorityRange},
thread::kernel_thread::{create_new_kernel_task, ThreadOptions},
Thread,
};
@ -50,9 +48,10 @@ impl Worker {
});
let mut cpu_affinity = CpuSet::new_empty();
cpu_affinity.add(bound_cpu);
let mut priority = Priority::normal();
let mut priority = Priority::default();
if worker_pool.upgrade().unwrap().is_high_priority() {
priority = Priority::high();
// FIXME: remove the use of real-time priority.
priority = Priority::new(PriorityRange::new(0));
}
let bound_task = create_new_kernel_task(
ThreadOptions::new(task_fn)

View File

@ -7,15 +7,12 @@ use core::{
time::Duration,
};
use ostd::{
cpu::CpuSet,
sync::WaitQueue,
task::{Priority, Task},
};
use ostd::{cpu::CpuSet, sync::WaitQueue, task::Task};
use super::{simple_scheduler::SimpleScheduler, worker::Worker, WorkItem, WorkPriority, WorkQueue};
use crate::{
prelude::*,
sched::priority::{Priority, PriorityRange},
thread::kernel_thread::{create_new_kernel_task, ThreadOptions},
Thread,
};
@ -236,9 +233,13 @@ impl Monitor {
current_monitor.run_monitor_loop();
});
let cpu_affinity = CpuSet::new_full();
// FIXME: remove the use of real-time priority.
// Logically all monitors should be of default normal priority.
// This workaround is to make the monitor of high-priority worker pool
// starvation-free under the current scheduling policy.
let priority = match priority {
WorkPriority::High => Priority::high(),
WorkPriority::Normal => Priority::normal(),
WorkPriority::High => Priority::new(PriorityRange::new(0)),
WorkPriority::Normal => Priority::default(),
};
let bound_task = create_new_kernel_task(
ThreadOptions::new(task_fn)

View File

@ -16,7 +16,7 @@ use processor::current_task;
pub use self::{
preempt::{disable_preempt, DisabledPreemptGuard},
scheduler::info::{AtomicCpuId, Priority, TaskScheduleInfo},
scheduler::info::{AtomicCpuId, TaskScheduleInfo},
};
pub(crate) use crate::arch::task::{context_switch, TaskContext};
use crate::{cpu::CpuSet, prelude::*, user::UserSpace};
@ -124,7 +124,6 @@ pub struct TaskOptions {
func: Option<Box<dyn Fn() + Send + Sync>>,
data: Option<Box<dyn Any + Send + Sync>>,
user_space: Option<Arc<UserSpace>>,
priority: Priority,
cpu_affinity: CpuSet,
}
@ -138,7 +137,6 @@ impl TaskOptions {
func: Some(Box::new(func)),
data: None,
user_space: None,
priority: Priority::normal(),
cpu_affinity: CpuSet::new_full(),
}
}
@ -167,12 +165,6 @@ impl TaskOptions {
self
}
/// Sets the priority of the task.
pub fn priority(mut self, priority: Priority) -> Self {
self.priority = priority;
self
}
/// Sets the CPU affinity mask for the task.
///
/// The `cpu_affinity` parameter represents
@ -220,7 +212,6 @@ impl TaskOptions {
kstack,
schedule_info: TaskScheduleInfo {
cpu: AtomicCpuId::default(),
priority: self.priority,
cpu_affinity: self.cpu_affinity,
},
};

View File

@ -15,83 +15,12 @@ use crate::cpu::CpuSet;
/// [existential types](https://github.com/rust-lang/rfcs/pull/2492) do not
/// exist yet. So we decide to define them in OSTD.
pub struct TaskScheduleInfo {
/// Priority of the task.
pub priority: Priority,
/// The CPU that the task would like to be running on.
pub cpu: AtomicCpuId,
/// The CPUs that this task can run on.
pub cpu_affinity: CpuSet,
}
/// The priority of a real-time task.
pub const REAL_TIME_TASK_PRIORITY: u16 = 100;
/// The priority of a task.
///
/// Similar to Linux, a larger value represents a lower priority,
/// with a range of 0 to 139. Priorities ranging from 0 to 99 are considered real-time,
/// while those ranging from 100 to 139 are considered normal.
#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
pub struct Priority(u16);
impl Priority {
const LOWEST: u16 = 139;
const LOW: u16 = 110;
const NORMAL: u16 = 100;
const HIGH: u16 = 10;
const HIGHEST: u16 = 0;
/// Creates a new `Priority` with the specified value.
///
/// # Panics
///
/// Panics if the `val` is greater than 139.
pub const fn new(val: u16) -> Self {
assert!(val <= Self::LOWEST);
Self(val)
}
/// Returns a `Priority` representing the lowest priority (139).
pub const fn lowest() -> Self {
Self::new(Self::LOWEST)
}
/// Returns a `Priority` representing a low priority.
pub const fn low() -> Self {
Self::new(Self::LOW)
}
/// Returns a `Priority` representing a normal priority.
pub const fn normal() -> Self {
Self::new(Self::NORMAL)
}
/// Returns a `Priority` representing a high priority.
pub const fn high() -> Self {
Self::new(Self::HIGH)
}
/// Returns a `Priority` representing the highest priority (0).
pub const fn highest() -> Self {
Self::new(Self::HIGHEST)
}
/// Sets the value of the `Priority`.
pub const fn set(&mut self, val: u16) {
self.0 = val;
}
/// Returns the value of the `Priority`.
pub const fn get(self) -> u16 {
self.0
}
/// Checks if the `Priority` is considered a real-time priority.
pub const fn is_real_time(&self) -> bool {
self.0 < REAL_TIME_TASK_PRIORITY
}
}
/// An atomic CPUID container.
pub struct AtomicCpuId(AtomicU32);