ostd/task/scheduler/info.rs
1// SPDX-License-Identifier: MPL-2.0
2
3//! Scheduling related information in a task.
4
5use core::sync::atomic::{AtomicU32, Ordering};
6
7use crate::{cpu::CpuId, task::Task};
8
9/// Fields of a task that OSTD will never touch.
10///
11/// The type ought to be defined by the OSTD user and injected into the task.
12/// They are not part of the dynamic task data because it's slower there for
13/// the user-defined scheduler to access. The better ways to let the user
14/// define them, such as
15/// [existential types](https://github.com/rust-lang/rfcs/pull/2492) do not
16/// exist yet. So we decide to define them in OSTD.
17#[derive(Debug)]
18pub struct TaskScheduleInfo {
19 /// The CPU that the task would like to be running on.
20 pub cpu: AtomicCpuId,
21}
22
23/// An atomic CPUID container.
24#[derive(Debug)]
25pub struct AtomicCpuId(AtomicU32);
26
27impl AtomicCpuId {
28 /// The null value of CPUID.
29 ///
30 /// An `AtomicCpuId` with `AtomicCpuId::NONE` as its inner value is empty.
31 const NONE: u32 = u32::MAX;
32
33 /// Sets the inner value of an `AtomicCpuId` if it's empty.
34 ///
35 /// The return value is a result indicating whether the new value was written
36 /// and containing the previous value. If the previous value is empty, it returns
37 /// `Ok(())`. Otherwise, it returns `Err(previous_value)` which the previous
38 /// value is a valid CPU ID.
39 pub fn set_if_is_none(&self, cpu_id: CpuId) -> core::result::Result<(), CpuId> {
40 self.0
41 .compare_exchange(
42 Self::NONE,
43 cpu_id.into(),
44 Ordering::Relaxed,
45 Ordering::Relaxed,
46 )
47 .map(|_| ())
48 .map_err(|prev| (prev as usize).try_into().unwrap())
49 }
50
51 /// Sets the inner value of an `AtomicCpuId` anyway.
52 pub fn set_anyway(&self, cpu_id: CpuId) {
53 self.0.store(cpu_id.into(), Ordering::Relaxed);
54 }
55
56 /// Sets the inner value of an `AtomicCpuId` to `AtomicCpuId::NONE`, i.e. makes
57 /// an `AtomicCpuId` empty.
58 pub fn set_to_none(&self) {
59 self.0.store(Self::NONE, Ordering::Relaxed);
60 }
61
62 /// Gets the inner value of an `AtomicCpuId`.
63 pub fn get(&self) -> Option<CpuId> {
64 let val = self.0.load(Ordering::Relaxed);
65 if val == Self::NONE {
66 None
67 } else {
68 Some((val as usize).try_into().ok()?)
69 }
70 }
71}
72
73impl Default for AtomicCpuId {
74 fn default() -> Self {
75 Self(AtomicU32::new(Self::NONE))
76 }
77}
78
79impl CommonSchedInfo for Task {
80 fn cpu(&self) -> &AtomicCpuId {
81 &self.schedule_info().cpu
82 }
83}
84
85/// Trait for fetching common scheduling information.
86pub trait CommonSchedInfo {
87 /// Gets the CPU that the task is running on or lately ran on.
88 fn cpu(&self) -> &AtomicCpuId;
89}