1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
#[cfg(feature = "metadata-name")]
use core::cell::Cell;
use core::future::{Future, poll_fn};
#[cfg(feature = "scheduler-priority")]
use core::sync::atomic::{AtomicU8, Ordering};
use core::task::Poll;
#[cfg(feature = "metadata-name")]
use critical_section::Mutex;
use crate::raw;
#[cfg(feature = "scheduler-deadline")]
use crate::raw::Deadline;
/// Metadata associated with a task.
pub struct Metadata {
#[cfg(feature = "metadata-name")]
name: Mutex<Cell<Option<&'static str>>>,
#[cfg(feature = "scheduler-priority")]
priority: AtomicU8,
#[cfg(feature = "scheduler-deadline")]
deadline: raw::Deadline,
}
impl Metadata {
pub(crate) const fn new() -> Self {
Self {
#[cfg(feature = "metadata-name")]
name: Mutex::new(Cell::new(None)),
#[cfg(feature = "scheduler-priority")]
priority: AtomicU8::new(0),
// NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This
// will be lazily initalized in `initialize_impl`
#[cfg(feature = "scheduler-deadline")]
deadline: raw::Deadline::new_unset(),
}
}
pub(crate) fn reset(&self) {
#[cfg(feature = "metadata-name")]
critical_section::with(|cs| self.name.borrow(cs).set(None));
#[cfg(feature = "scheduler-priority")]
self.set_priority(0);
// By default, deadlines are set to the maximum value, so that any task WITH
// a set deadline will ALWAYS be scheduled BEFORE a task WITHOUT a set deadline
#[cfg(feature = "scheduler-deadline")]
self.unset_deadline();
}
/// Get the metadata for the current task.
///
/// You can use this to read or modify the current task's metadata.
///
/// This function is `async` just to get access to the current async
/// context. It returns instantly, it does not block/yield.
pub fn for_current_task() -> impl Future<Output = &'static Self> {
poll_fn(|cx| Poll::Ready(raw::task_from_waker(cx.waker()).metadata()))
}
/// Get this task's name
///
/// NOTE: this takes a critical section.
#[cfg(feature = "metadata-name")]
pub fn name(&self) -> Option<&'static str> {
critical_section::with(|cs| self.name.borrow(cs).get())
}
/// Set this task's name
///
/// NOTE: this takes a critical section.
#[cfg(feature = "metadata-name")]
pub fn set_name(&self, name: &'static str) {
critical_section::with(|cs| self.name.borrow(cs).set(Some(name)))
}
/// Get this task's priority.
#[cfg(feature = "scheduler-priority")]
pub fn priority(&self) -> u8 {
self.priority.load(Ordering::Relaxed)
}
/// Set this task's priority.
#[cfg(feature = "scheduler-priority")]
pub fn set_priority(&self, priority: u8) {
self.priority.store(priority, Ordering::Relaxed)
}
/// Get this task's deadline.
#[cfg(feature = "scheduler-deadline")]
pub fn deadline(&self) -> u64 {
self.deadline.instant_ticks()
}
/// Set this task's deadline.
///
/// This method does NOT check whether the deadline has already passed.
#[cfg(feature = "scheduler-deadline")]
pub fn set_deadline(&self, instant_ticks: u64) {
self.deadline.set(instant_ticks);
}
/// Remove this task's deadline.
/// This brings it back to the defaul where it's not scheduled ahead of other tasks.
#[cfg(feature = "scheduler-deadline")]
pub fn unset_deadline(&self) {
self.deadline.set(Deadline::UNSET_TICKS);
}
/// Set this task's deadline `duration_ticks` in the future from when
/// this future is polled. This deadline is saturated to the max tick value.
///
/// Analogous to `Timer::after`.
#[cfg(all(feature = "scheduler-deadline", feature = "embassy-time-driver"))]
pub fn set_deadline_after(&self, duration_ticks: u64) {
let now = embassy_time_driver::now();
// Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
// it for now, we can probably make this wrapping_add for performance
// reasons later.
let deadline = now.saturating_add(duration_ticks);
self.set_deadline(deadline);
}
/// Set the this task's deadline `increment_ticks` from the previous deadline.
///
/// This deadline is saturated to the max tick value.
///
/// Note that by default (unless otherwise set), tasks start life with the deadline
/// not set, which means this method will have no effect.
///
/// Analogous to one increment of `Ticker::every().next()`.
///
/// Returns the deadline that was set.
#[cfg(feature = "scheduler-deadline")]
pub fn increment_deadline(&self, duration_ticks: u64) {
let last = self.deadline();
// Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
// it for now, we can probably make this wrapping_add for performance
// reasons later.
let deadline = last.saturating_add(duration_ticks);
self.set_deadline(deadline);
}
}
|