Skip to content

Commit 42a097d

Browse files
authored
Move ThreadFlags to embassy impl (#4383)
1 parent 75ed0d1 commit 42a097d

File tree

2 files changed

+97
-107
lines changed

2 files changed

+97
-107
lines changed

esp-rtos/src/embassy/mod.rs

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,107 @@
11
//! OS-aware embassy executors.
22
3-
use core::{cell::UnsafeCell, mem::MaybeUninit, sync::atomic::Ordering};
3+
use core::{cell::UnsafeCell, mem::MaybeUninit, ptr::NonNull, sync::atomic::Ordering};
44

55
use embassy_executor::{SendSpawner, Spawner, raw};
6-
use esp_hal::interrupt::{InterruptHandler, Priority, software::SoftwareInterrupt};
7-
#[cfg(multi_core)]
8-
use esp_hal::system::Cpu;
6+
use esp_hal::{
7+
interrupt::{InterruptHandler, Priority, software::SoftwareInterrupt},
8+
system::Cpu,
9+
time::{Duration, Instant},
10+
};
11+
use esp_sync::NonReentrantMutex;
912
use macros::ram;
1013
use portable_atomic::AtomicPtr;
1114

12-
use crate::task::flags::ThreadFlag;
15+
use crate::{
16+
SCHEDULER,
17+
task::{TaskExt, TaskPtr},
18+
};
19+
20+
pub(crate) struct FlagsInner {
21+
owner: TaskPtr,
22+
waiting: Option<TaskPtr>,
23+
set: bool,
24+
}
25+
impl FlagsInner {
26+
fn take(&mut self) -> bool {
27+
if self.set {
28+
// The flag was set while we weren't looking.
29+
self.set = false;
30+
true
31+
} else {
32+
// `waiting` signals that the owner should be resumed when the flag is set. Copying
33+
// the task pointer is an optimization that allows clearing the
34+
// waiting state without computing the address of a separate field.
35+
self.waiting = Some(self.owner);
36+
37+
false
38+
}
39+
}
40+
}
41+
42+
/// A single event bit, optimized for the thread-mode embassy executor.
43+
///
44+
/// This takes shortcuts, which make it unsuitable for general purpose use (such as no wait
45+
/// queue, no timeout, assumes a single thread waits for the flag, there is only a single bit of
46+
/// flag information).
47+
struct ThreadFlag {
48+
inner: NonReentrantMutex<FlagsInner>,
49+
}
50+
51+
impl ThreadFlag {
52+
fn new() -> Self {
53+
let owner = SCHEDULER.with(|scheduler| {
54+
let current_cpu = Cpu::current() as usize;
55+
if let Some(current_task) = scheduler.per_cpu[current_cpu].current_task {
56+
current_task
57+
} else {
58+
// We're cheating, the task hasn't been initialized yet.
59+
NonNull::from(&scheduler.per_cpu[current_cpu].main_task)
60+
}
61+
});
62+
Self {
63+
inner: NonReentrantMutex::new(FlagsInner {
64+
owner,
65+
waiting: None,
66+
set: false,
67+
}),
68+
}
69+
}
70+
71+
fn with<R>(&self, f: impl FnOnce(&mut FlagsInner) -> R) -> R {
72+
self.inner.with(|inner| f(inner))
73+
}
74+
75+
fn set(&self) {
76+
self.with(|inner| {
77+
if let Some(waiting) = inner.waiting.take() {
78+
// The task is waiting, there is no need to set the flag - resuming the thread
79+
// is all the signal we need.
80+
waiting.resume();
81+
} else {
82+
// The task isn't waiting, set the flag.
83+
inner.set = true;
84+
}
85+
});
86+
}
87+
88+
fn get(&self) -> bool {
89+
self.with(|inner| inner.set)
90+
}
91+
92+
fn wait(&self) {
93+
self.with(|inner| {
94+
if !inner.take() {
95+
// SCHEDULER.sleep_until, but we know the current task's ID, and we know there
96+
// is no timeout.
97+
SCHEDULER.with(|scheduler| {
98+
scheduler.sleep_task_until(inner.owner, Instant::EPOCH + Duration::MAX);
99+
crate::task::yield_task();
100+
});
101+
}
102+
});
103+
}
104+
}
13105

14106
#[unsafe(export_name = "__pender")]
15107
#[ram]

esp-rtos/src/task/mod.rs

Lines changed: 0 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -319,108 +319,6 @@ impl<E: TaskListElement> TaskQueue<E> {
319319
}
320320
}
321321

322-
#[cfg(feature = "embassy")]
323-
pub(crate) mod flags {
324-
use core::ptr::NonNull;
325-
326-
use esp_hal::{
327-
system::Cpu,
328-
time::{Duration, Instant},
329-
};
330-
use esp_sync::NonReentrantMutex;
331-
332-
use crate::{
333-
SCHEDULER,
334-
task::{TaskExt, TaskPtr},
335-
};
336-
337-
pub(crate) struct FlagsInner {
338-
owner: TaskPtr,
339-
waiting: Option<TaskPtr>,
340-
set: bool,
341-
}
342-
impl FlagsInner {
343-
fn take(&mut self) -> bool {
344-
if self.set {
345-
// The flag was set while we weren't looking.
346-
self.set = false;
347-
true
348-
} else {
349-
// `waiting` signals that the owner should be resumed when the flag is set. Copying
350-
// the task pointer is an optimization that allows clearing the
351-
// waiting state without computing the address of a separate field.
352-
self.waiting = Some(self.owner);
353-
354-
false
355-
}
356-
}
357-
}
358-
359-
/// A single event bit, optimized for the thread-mode embassy executor.
360-
///
361-
/// This takes shortcuts, which make it unsuitable for general purpose use (such as no wait
362-
/// queue, no timeout, assumes a single thread waits for the flag, there is only a single bit of
363-
/// flag information).
364-
pub(crate) struct ThreadFlag {
365-
inner: NonReentrantMutex<FlagsInner>,
366-
}
367-
368-
impl ThreadFlag {
369-
pub(crate) fn new() -> Self {
370-
let owner = SCHEDULER.with(|scheduler| {
371-
let current_cpu = Cpu::current() as usize;
372-
if let Some(current_task) = scheduler.per_cpu[current_cpu].current_task {
373-
current_task
374-
} else {
375-
// We're cheating, the task hasn't been initialized yet.
376-
NonNull::from(&scheduler.per_cpu[current_cpu].main_task)
377-
}
378-
});
379-
Self {
380-
inner: NonReentrantMutex::new(FlagsInner {
381-
owner,
382-
waiting: None,
383-
set: false,
384-
}),
385-
}
386-
}
387-
388-
fn with<R>(&self, f: impl FnOnce(&mut FlagsInner) -> R) -> R {
389-
self.inner.with(|inner| f(inner))
390-
}
391-
392-
pub(crate) fn set(&self) {
393-
self.with(|inner| {
394-
if let Some(waiting) = inner.waiting.take() {
395-
// The task is waiting, there is no need to set the flag - resuming the thread
396-
// is all the signal we need.
397-
waiting.resume();
398-
} else {
399-
// The task isn't waiting, set the flag.
400-
inner.set = true;
401-
}
402-
});
403-
}
404-
405-
pub(crate) fn get(&self) -> bool {
406-
self.with(|inner| inner.set)
407-
}
408-
409-
pub(crate) fn wait(&self) {
410-
self.with(|inner| {
411-
if !inner.take() {
412-
// SCHEDULER.sleep_until, but we know the current task's ID, and we know there
413-
// is no timeout.
414-
SCHEDULER.with(|scheduler| {
415-
scheduler.sleep_task_until(inner.owner, Instant::EPOCH + Duration::MAX);
416-
crate::task::yield_task();
417-
});
418-
}
419-
});
420-
}
421-
}
422-
}
423-
424322
#[repr(C)]
425323
pub(crate) struct Task {
426324
pub cpu_context: CpuContext,

0 commit comments

Comments
 (0)