sparreal_kernel/os/async/
task.rs1use core::future::Future;
6use core::pin::Pin;
7use core::task::{Context, Poll, Waker};
8
9use alloc::boxed::Box;
10use alloc::sync::Arc;
11
12use crate::os::sync::spinlock::IrqSpinlock;
13use crate::os::time;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
17pub struct TaskId(pub u64);
18
19impl TaskId {
20 pub fn new() -> Self {
22 use core::sync::atomic::{AtomicU64, Ordering};
23 static COUNTER: AtomicU64 = AtomicU64::new(1);
24 TaskId(COUNTER.fetch_add(1, Ordering::Relaxed))
25 }
26}
27
28impl Default for TaskId {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum TaskState {
37 Pending,
39 Woken,
41 Running,
43 Completed,
45}
46
47#[derive(Debug)]
49pub struct TaskMetadata {
50 pub id: TaskId,
52 pub state: TaskState,
54 pub created_at: u64,
56 pub last_wake_at: u64,
58 pub last_run_at: Option<u64>,
60 pub run_count: u64,
62}
63
64impl TaskMetadata {
65 pub fn new(id: TaskId) -> Self {
67 let now = time::since_boot().as_millis() as u64;
68 Self {
69 id,
70 state: TaskState::Woken, created_at: now,
72 last_wake_at: now,
73 last_run_at: None,
74 run_count: 0,
75 }
76 }
77
78 pub fn is_expired(&self, timeout_ms: u64) -> bool {
80 if let Some(last_run) = self.last_run_at {
81 time::since_boot().as_millis() as u64 - last_run > timeout_ms
82 } else {
83 time::since_boot().as_millis() as u64 - self.created_at > timeout_ms
85 }
86 }
87
88 pub fn update_execution(&mut self) {
90 self.last_run_at = Some(time::since_boot().as_millis() as u64);
91 self.run_count += 1;
92 self.state = TaskState::Running;
93 }
94
95 pub fn mark_woken(&mut self) {
97 self.last_wake_at = time::since_boot().as_millis() as u64;
98 self.state = TaskState::Woken;
99 }
100
101 pub fn mark_completed(&mut self) {
103 self.state = TaskState::Completed;
104 }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
109pub struct TaskPriority {
110 pub is_woken: bool,
112 pub timestamp: u64,
114 pub task_id: TaskId,
116}
117
118impl TaskPriority {
119 pub fn new(metadata: &TaskMetadata) -> Self {
121 Self {
122 is_woken: metadata.state == TaskState::Woken,
123 timestamp: metadata.last_wake_at,
124 task_id: metadata.id,
125 }
126 }
127}
128
129pub struct TaskRef {
131 pub metadata: IrqSpinlock<TaskMetadata>,
133 pub future: IrqSpinlock<Pin<Box<dyn Future<Output = ()> + Send>>>,
135}
136
137impl core::fmt::Debug for TaskRef {
138 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
139 let id = self.metadata.lock().id;
140 write!(f, "TaskRef({id:?})")
141 }
142}
143
144impl TaskRef {
145 pub fn new<F>(future: F, metadata: TaskMetadata) -> Self
147 where
148 F: Future<Output = ()> + Send + 'static,
149 {
150 Self {
151 metadata: IrqSpinlock::new(metadata),
152 future: IrqSpinlock::new(Box::pin(future)),
153 }
154 }
155
156 pub fn id(&self) -> TaskId {
158 self.metadata.lock().id
159 }
160
161 pub fn is_completed(&self) -> bool {
163 self.metadata.lock().state == TaskState::Completed
164 }
165
166 pub fn priority(&self) -> TaskPriority {
168 TaskPriority::new(&self.metadata.lock())
169 }
170
171 pub fn poll(&self, waker: &Waker) -> Poll<()> {
173 let metadata = &mut self.metadata.lock();
174 if metadata.state == TaskState::Completed {
175 return Poll::Ready(());
176 }
177
178 metadata.update_execution();
179
180 let future = &mut self.future.lock();
181 let mut cx = Context::from_waker(waker);
182
183 match future.as_mut().poll(&mut cx) {
184 Poll::Ready(()) => {
185 metadata.mark_completed();
186 Poll::Ready(())
187 }
188 Poll::Pending => {
189 metadata.state = TaskState::Pending;
190 Poll::Pending
191 }
192 }
193 }
194}
195
196#[derive(Debug, Clone)]
198pub struct TaskHandle {
199 pub id: TaskId,
201 task_ref: Option<Arc<TaskRef>>,
203}
204
205impl TaskHandle {
206 pub fn new(id: TaskId) -> Self {
208 Self { id, task_ref: None }
209 }
210
211 pub fn with_ref(id: TaskId, task_ref: Arc<TaskRef>) -> Self {
213 Self {
214 id,
215 task_ref: Some(task_ref),
216 }
217 }
218
219 pub fn wake(&self) -> bool {
221 if let Some(task_ref) = &self.task_ref {
222 task_ref.metadata.lock().mark_woken();
223 true
224 } else {
225 false
226 }
227 }
228}