Skip to content

Commit 60d3199

Browse files
authored
RTOS: make core selection RunQueue's job, remove unnecessary panicking code from mark_task_ready (#4290)
* Make core selection the job of RunQueue * Remove some panics * Tweak docs, fix warning * Ensure the same offset is used for esp-hal and esp-rtos, fix docs * Clippy * Insert a short delay into the blocking loop
1 parent 85b11c4 commit 60d3199

File tree

6 files changed

+297
-153
lines changed

6 files changed

+297
-153
lines changed

esp-rtos/src/lib.rs

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,15 @@ use core::mem::MaybeUninit;
9595
pub(crate) use esp_alloc::InternalMemory;
9696
#[cfg(any(multi_core, riscv))]
9797
use esp_hal::interrupt::software::SoftwareInterrupt;
98+
#[cfg(systimer)]
99+
use esp_hal::timer::systimer::Alarm;
100+
#[cfg(timergroup)]
101+
use esp_hal::timer::timg::Timer;
98102
use esp_hal::{
99103
Blocking,
100104
system::Cpu,
101105
time::{Duration, Instant},
102-
timer::{AnyTimer, OneShotTimer},
106+
timer::{AnyTimer, OneShotTimer, any::Degrade},
103107
};
104108
#[cfg(multi_core)]
105109
use esp_hal::{
@@ -205,9 +209,9 @@ mod esp_alloc {
205209
}
206210
}
207211

208-
/// A trait to allow better UX for initializing esp-rtos.
212+
/// Timers that can be used as time drivers.
209213
///
210-
/// This trait is meant to be used only for the `init` function.
214+
/// This trait is meant to be used only for the [`start`] function.
211215
pub trait TimerSource: private::Sealed + 'static {
212216
/// Returns the timer source.
213217
fn timer(self) -> TimeBase;
@@ -220,28 +224,44 @@ mod private {
220224
impl private::Sealed for TimeBase {}
221225
impl private::Sealed for AnyTimer<'static> {}
222226
#[cfg(timergroup)]
223-
impl private::Sealed for esp_hal::timer::timg::Timer<'static> {}
227+
impl private::Sealed for Timer<'static> {}
224228
#[cfg(systimer)]
225-
impl private::Sealed for esp_hal::timer::systimer::Alarm<'static> {}
229+
impl private::Sealed for Alarm<'static> {}
230+
231+
impl TimerSource for TimeBase {
232+
fn timer(self) -> TimeBase {
233+
self
234+
}
235+
}
226236

227-
impl<T> TimerSource for T
228-
where
229-
T: esp_hal::timer::any::Degrade + private::Sealed + 'static,
230-
{
237+
impl TimerSource for AnyTimer<'static> {
231238
fn timer(self) -> TimeBase {
232-
let any_timer: AnyTimer<'static> = self.degrade();
233-
TimeBase::new(any_timer)
239+
TimeBase::new(self)
240+
}
241+
}
242+
243+
#[cfg(timergroup)]
244+
impl TimerSource for Timer<'static> {
245+
fn timer(self) -> TimeBase {
246+
TimeBase::new(self.degrade())
247+
}
248+
}
249+
250+
#[cfg(systimer)]
251+
impl TimerSource for Alarm<'static> {
252+
fn timer(self) -> TimeBase {
253+
TimeBase::new(self.degrade())
234254
}
235255
}
236256

237257
/// Starts the scheduler.
238258
///
239259
/// The current context will be converted into the main task, and will be pinned to the first core.
240260
///
241-
/// This function is equivalent to [start_with_idle_hook], with the default idle hook. The default
261+
/// This function is equivalent to [`start_with_idle_hook`], with the default idle hook. The default
242262
/// idle hook will wait for an interrupt.
243263
///
244-
/// For information about the other arguments, see [start_with_idle_hook].
264+
/// For information about the arguments, see [`start_with_idle_hook`].
245265
pub fn start(timer: impl TimerSource, #[cfg(riscv)] int0: SoftwareInterrupt<'static, 0>) {
246266
start_with_idle_hook(
247267
timer,
@@ -265,6 +285,7 @@ pub fn start(timer: impl TimerSource, #[cfg(riscv)] int0: SoftwareInterrupt<'sta
265285
/// - A timg `Timer` instance
266286
/// - A systimer `Alarm` instance
267287
/// - An `AnyTimer` instance
288+
/// - A `OneShotTimer` instance
268289
#[doc = ""]
269290
#[cfg_attr(
270291
riscv,
@@ -337,6 +358,10 @@ pub fn start_with_idle_hook(
337358
///
338359
/// The supplied stack and function will be used as the main thread of the second core. The thread
339360
/// will be pinned to the second core.
361+
///
362+
/// You can return from the second core's main thread function. This will cause the scheduler to
363+
/// enter the idle state, but the second core will continue to run interrupt handlers and other
364+
/// tasks.
340365
#[cfg(multi_core)]
341366
pub fn start_second_core<const STACK_SIZE: usize>(
342367
cpu_control: CPU_CTRL,
@@ -351,10 +376,7 @@ pub fn start_second_core<const STACK_SIZE: usize>(
351376
int0,
352377
int1,
353378
stack,
354-
Some(esp_config::esp_config_int!(
355-
usize,
356-
"ESP_HAL_CONFIG_STACK_GUARD_OFFSET"
357-
)),
379+
None,
358380
func,
359381
);
360382
}
@@ -365,6 +387,14 @@ pub fn start_second_core<const STACK_SIZE: usize>(
365387
///
366388
/// The supplied stack and function will be used as the main thread of the second core. The thread
367389
/// will be pinned to the second core.
390+
///
391+
/// The stack guard offset is used to reserve a portion of the stack for the stack guard, for safety
392+
/// purposes. Passing `None` will result in the default value configured by the
393+
/// `ESP_HAL_CONFIG_STACK_GUARD_OFFSET` esp-hal configuration.
394+
///
395+
/// You can return from the second core's main thread function. This will cause the scheduler to
396+
/// enter the idle state, but the second core will continue to run interrupt handlers and other
397+
/// tasks.
368398
#[cfg(multi_core)]
369399
pub fn start_second_core_with_stack_guard_offset<const STACK_SIZE: usize>(
370400
cpu_control: CPU_CTRL,
@@ -390,9 +420,14 @@ pub fn start_second_core_with_stack_guard_offset<const STACK_SIZE: usize>(
390420
),
391421
};
392422

423+
let stack_guard_offset = stack_guard_offset.unwrap_or(esp_config::esp_config_int!(
424+
usize,
425+
"ESP_HAL_CONFIG_STACK_GUARD_OFFSET"
426+
));
427+
393428
let mut cpu_control = CpuControl::new(cpu_control);
394429
let guard = cpu_control
395-
.start_app_core_with_stack_guard_offset(stack, stack_guard_offset, move || {
430+
.start_app_core_with_stack_guard_offset(stack, Some(stack_guard_offset), move || {
396431
trace!("Second core running");
397432
task::setup_smp(int1);
398433
SCHEDULER.with(move |scheduler| {
@@ -405,12 +440,7 @@ pub fn start_second_core_with_stack_guard_offset<const STACK_SIZE: usize>(
405440

406441
// esp-hal may be configured to use a watchpoint. To work around that, we read the
407442
// memory at the stack guard, and we'll use whatever we find as the main task's
408-
// stack guard value.
409-
let stack_guard_offset = stack_guard_offset.unwrap_or(esp_config::esp_config_int!(
410-
usize,
411-
"ESP_HAL_CONFIG_STACK_GUARD_OFFSET"
412-
));
413-
443+
// stack guard value, instead of writing our own stack guard value.
414444
let stack_bottom = ptrs.stack.cast::<u32>();
415445
let stack_guard = unsafe { stack_bottom.byte_add(stack_guard_offset) };
416446

@@ -429,6 +459,11 @@ pub fn start_second_core_with_stack_guard_offset<const STACK_SIZE: usize>(
429459
})
430460
.unwrap();
431461

462+
// Spin until the second core scheduler is initialized
463+
while SCHEDULER.with(|s| !s.per_cpu[1].initialized) {
464+
esp_hal::rom::ets_delay_us(1);
465+
}
466+
432467
core::mem::forget(guard);
433468
}
434469

0 commit comments

Comments
 (0)