Skip to content

Commit 6dd0edd

Browse files
authored
Teeny-tiny scheduler improvements (#4061)
* Avoid swapping to the same task * Allow scheduling multiple tasks to be deleted * Add task state
1 parent 24d2122 commit 6dd0edd

File tree

2 files changed

+68
-23
lines changed

2 files changed

+68
-23
lines changed

esp-preempt/src/lib.rs

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -160,48 +160,76 @@ impl SchedulerState {
160160
}
161161
}
162162

163-
#[cfg(xtensa)]
164-
fn switch_task(&mut self, trap_frame: &mut esp_hal::trapframe::TrapFrame) {
165-
task::save_task_context(unsafe { &mut *self.current_task }, trap_frame);
166-
167-
if !self.to_delete.is_null() {
163+
fn delete_marked_tasks(&mut self) {
164+
while !self.to_delete.is_null() {
168165
let task_to_delete = core::mem::take(&mut self.to_delete);
166+
self.to_delete = unsafe { (*task_to_delete).next_to_delete };
169167
self.delete_task(task_to_delete);
170168
}
169+
}
170+
171+
fn select_next_task(&mut self) -> Option<*mut Context> {
172+
let mut current = self.current_task;
173+
loop {
174+
let next_task = unsafe { (*current).next };
175+
176+
if next_task == self.current_task {
177+
// We didn't find a new task to switch to.
178+
// TODO: mark the current task as Running
179+
// Once we have actual task states, yield should marked the current task as Ready,
180+
// other stuff as Waiting.
181+
return None;
182+
}
171183

172-
unsafe { self.current_task = (*self.current_task).next };
184+
if unsafe { (*next_task).state }.is_ready() {
185+
// TODO: mark the selected task as Running
186+
return Some(next_task);
187+
}
188+
current = next_task;
189+
}
190+
}
191+
192+
#[cfg(xtensa)]
193+
fn switch_task(&mut self, trap_frame: &mut esp_hal::trapframe::TrapFrame) {
194+
self.delete_marked_tasks();
195+
196+
let Some(next_task) = self.select_next_task() else {
197+
return;
198+
};
199+
200+
task::save_task_context(unsafe { &mut *self.current_task }, trap_frame);
201+
202+
self.current_task = next_task;
173203

174204
task::restore_task_context(unsafe { &mut *self.current_task }, trap_frame);
175205
}
176206

177207
#[cfg(riscv)]
178208
fn switch_task(&mut self) {
179-
if !self.to_delete.is_null() {
180-
let task_to_delete = core::mem::take(&mut self.to_delete);
181-
self.delete_task(task_to_delete);
182-
}
209+
self.delete_marked_tasks();
183210

184-
let task = self.current_task;
185-
let context = unsafe { &mut (*task).trap_frame };
186-
let old_ctx = core::ptr::addr_of_mut!(*context);
211+
let Some(next_task) = self.select_next_task() else {
212+
return;
213+
};
187214

188-
let task = unsafe { (*self.current_task).next };
189-
let context = unsafe { &mut (*task).trap_frame };
190-
let new_ctx = core::ptr::addr_of_mut!(*context);
215+
let old_ctx = unsafe { &raw mut (*self.current_task).trap_frame };
216+
let new_ctx = unsafe { &raw mut (*next_task).trap_frame };
191217

192218
if crate::task::arch_specific::task_switch(old_ctx, new_ctx) {
193219
unsafe { self.current_task = (*self.current_task).next };
194220
}
195221
}
196222

197-
fn schedule_task_deletion(&mut self, task: *mut Context) -> bool {
198-
if task.is_null() {
199-
self.to_delete = self.current_task;
200-
true
201-
} else {
202-
self.to_delete = task;
203-
core::ptr::eq(task, self.current_task)
223+
fn schedule_task_deletion(&mut self, mut task_to_delete: *mut Context) -> bool {
224+
if task_to_delete.is_null() {
225+
task_to_delete = self.current_task;
204226
}
227+
let is_current = core::ptr::eq(task_to_delete, self.current_task);
228+
229+
unsafe { (*task_to_delete).next_to_delete = self.to_delete };
230+
self.to_delete = task_to_delete;
231+
232+
is_current
205233
}
206234
}
207235

esp-preempt/src/task/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@ use esp_radio_preempt_driver::semaphore::{SemaphoreHandle, SemaphorePtr};
1414

1515
use crate::{InternalMemory, SCHEDULER_STATE, task, timer};
1616

17+
#[derive(Clone, Copy)]
18+
pub(crate) enum TaskState {
19+
Ready,
20+
}
21+
22+
impl TaskState {
23+
pub fn is_ready(self) -> bool {
24+
matches!(self, Self::Ready)
25+
}
26+
}
27+
1728
#[repr(C)]
1829
pub(crate) struct Context {
1930
#[cfg(riscv)]
@@ -22,6 +33,8 @@ pub(crate) struct Context {
2233
pub trap_frame: TrapFrame,
2334
pub thread_semaphore: Option<SemaphorePtr>,
2435
pub next: *mut Context,
36+
pub next_to_delete: *mut Context,
37+
pub state: TaskState,
2538
pub _allocated_stack: Box<[MaybeUninit<u8>], InternalMemory>,
2639
}
2740

@@ -41,6 +54,8 @@ impl Context {
4154
trap_frame: task::new_task_context(task_fn, param, stack_top),
4255
thread_semaphore: None,
4356
next: core::ptr::null_mut(),
57+
next_to_delete: core::ptr::null_mut(),
58+
state: TaskState::Ready,
4459
_allocated_stack: stack,
4560
}
4661
}
@@ -65,6 +80,8 @@ pub(super) fn allocate_main_task() {
6580
trap_frame: TrapFrame::default(),
6681
thread_semaphore: None,
6782
next: core::ptr::null_mut(),
83+
next_to_delete: core::ptr::null_mut(),
84+
state: TaskState::Ready,
6885
_allocated_stack: Box::<[u8], _>::new_uninit_slice_in(0, InternalMemory),
6986
},
7087
InternalMemory,

0 commit comments

Comments
 (0)