Skip to content

Commit cf2b162

Browse files
authored
Add queues to esp-preempt (#4043)
1 parent 38fd991 commit cf2b162

File tree

20 files changed

+844
-361
lines changed

20 files changed

+844
-361
lines changed

esp-alloc/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- Added chip-selection features (#4023)
13-
- New default feature (`compat`) enables implementations for `malloc`, `free`, `calloc`, `realloc` (#3890)
13+
- New default feature (`compat`) enables implementations for `malloc`, `free`, `calloc`, `realloc` and others (#3890, #4043)
1414

1515
### Changed
1616

esp-alloc/src/malloc.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ pub unsafe extern "C" fn free(ptr: *mut u8) {
4848
}
4949
}
5050

51+
#[unsafe(no_mangle)]
52+
pub unsafe extern "C" fn free_internal(ptr: *mut u8) {
53+
unsafe { free(ptr) }
54+
}
55+
5156
#[unsafe(no_mangle)]
5257
pub unsafe extern "C" fn calloc(number: u32, size: usize) -> *mut u8 {
5358
let total_size = number as usize * size;

esp-preempt/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ extern crate alloc;
2424
mod fmt;
2525

2626
mod mutex;
27+
mod queue;
2728
mod semaphore;
2829
mod task;
2930
mod timer;

esp-preempt/src/queue.rs

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
use alloc::{boxed::Box, vec};
2+
use core::ptr::NonNull;
3+
4+
use esp_hal::time::{Duration, Instant};
5+
use esp_radio_preempt_driver::{
6+
queue::{QueueImplementation, QueuePtr},
7+
register_queue_implementation,
8+
yield_task,
9+
};
10+
use esp_sync::NonReentrantMutex;
11+
12+
struct QueueInner {
13+
storage: Box<[u8]>,
14+
item_size: usize,
15+
capacity: usize,
16+
current_read: usize,
17+
current_write: usize,
18+
}
19+
20+
impl QueueInner {
21+
fn new(capacity: usize, item_size: usize) -> Self {
22+
Self {
23+
item_size,
24+
capacity,
25+
current_read: 0,
26+
current_write: 0,
27+
storage: vec![0; capacity * item_size].into_boxed_slice(),
28+
}
29+
}
30+
31+
fn get(&self, index: usize) -> &[u8] {
32+
let item_start = self.item_size * index;
33+
&self.storage[item_start..][..self.item_size]
34+
}
35+
36+
fn get_mut(&mut self, index: usize) -> &mut [u8] {
37+
let item_start = self.item_size * index;
38+
&mut self.storage[item_start..][..self.item_size]
39+
}
40+
41+
unsafe fn try_enqueue(&mut self, item: *const u8) -> bool {
42+
if self.len() == self.capacity {
43+
return false;
44+
}
45+
46+
let item = unsafe { core::slice::from_raw_parts(item, self.item_size) };
47+
48+
let dst = self.get_mut(self.current_write);
49+
dst.copy_from_slice(item);
50+
51+
self.current_write = (self.current_write + 1) % self.capacity;
52+
53+
true
54+
}
55+
56+
unsafe fn try_dequeue(&mut self, dst: *mut u8) -> bool {
57+
if self.len() == 0 {
58+
return false;
59+
}
60+
61+
let dst = unsafe { core::slice::from_raw_parts_mut(dst, self.item_size) };
62+
63+
let src = self.get(self.current_read);
64+
dst.copy_from_slice(src);
65+
66+
self.current_read = (self.current_read + 1) % self.capacity;
67+
68+
true
69+
}
70+
71+
fn len(&self) -> usize {
72+
if self.current_write >= self.current_read {
73+
self.current_write - self.current_read
74+
} else {
75+
self.capacity - self.current_read + self.current_write
76+
}
77+
}
78+
}
79+
80+
pub struct Queue {
81+
inner: NonReentrantMutex<QueueInner>,
82+
}
83+
84+
impl Queue {
85+
pub fn new(capacity: usize, item_size: usize) -> Self {
86+
Queue {
87+
inner: NonReentrantMutex::new(QueueInner::new(capacity, item_size)),
88+
}
89+
}
90+
91+
unsafe fn from_ptr<'a>(ptr: QueuePtr) -> &'a Self {
92+
unsafe { ptr.cast::<Self>().as_ref() }
93+
}
94+
95+
fn yield_loop_with_timeout(timeout_us: Option<u32>, mut cb: impl FnMut() -> bool) -> bool {
96+
let start = if timeout_us.is_some() {
97+
Instant::now()
98+
} else {
99+
Instant::EPOCH
100+
};
101+
102+
let timeout = timeout_us
103+
.map(|us| Duration::from_micros(us as u64))
104+
.unwrap_or(Duration::MAX);
105+
106+
loop {
107+
if cb() {
108+
return true;
109+
}
110+
111+
if timeout_us.is_some() && start.elapsed() > timeout {
112+
return false;
113+
}
114+
115+
yield_task();
116+
}
117+
}
118+
119+
unsafe fn send_to_back(&self, item: *const u8, timeout_us: Option<u32>) -> bool {
120+
Self::yield_loop_with_timeout(timeout_us, || unsafe { self.try_send_to_back(item) })
121+
}
122+
123+
unsafe fn try_send_to_back(&self, item: *const u8) -> bool {
124+
self.inner.with(|queue| unsafe { queue.try_enqueue(item) })
125+
}
126+
127+
unsafe fn receive(&self, item: *mut u8, timeout_us: Option<u32>) -> bool {
128+
Self::yield_loop_with_timeout(timeout_us, || unsafe { self.try_receive(item) })
129+
}
130+
131+
unsafe fn try_receive(&self, item: *mut u8) -> bool {
132+
self.inner.with(|queue| unsafe { queue.try_dequeue(item) })
133+
}
134+
135+
fn messages_waiting(&self) -> usize {
136+
self.inner.with(|queue| queue.len())
137+
}
138+
}
139+
140+
impl QueueImplementation for Queue {
141+
fn create(capacity: usize, item_size: usize) -> QueuePtr {
142+
let q = Box::new(Queue::new(capacity, item_size));
143+
NonNull::from(Box::leak(q)).cast()
144+
}
145+
146+
unsafe fn delete(queue: QueuePtr) {
147+
let q = unsafe { Box::from_raw(queue.cast::<Queue>().as_ptr()) };
148+
core::mem::drop(q);
149+
}
150+
151+
unsafe fn send_to_front(_queue: QueuePtr, _item: *const u8, _timeout_us: Option<u32>) -> bool {
152+
unimplemented!()
153+
}
154+
155+
unsafe fn send_to_back(queue: QueuePtr, item: *const u8, timeout_us: Option<u32>) -> bool {
156+
let queue = unsafe { Queue::from_ptr(queue) };
157+
158+
unsafe { queue.send_to_back(item, timeout_us) }
159+
}
160+
161+
unsafe fn try_send_to_back(queue: QueuePtr, item: *const u8) -> bool {
162+
let queue = unsafe { Queue::from_ptr(queue) };
163+
164+
unsafe { queue.try_send_to_back(item) }
165+
}
166+
167+
unsafe fn receive(queue: QueuePtr, item: *mut u8, timeout_us: Option<u32>) -> bool {
168+
let queue = unsafe { Queue::from_ptr(queue) };
169+
170+
unsafe { queue.receive(item, timeout_us) }
171+
}
172+
173+
unsafe fn try_receive(queue: QueuePtr, item: *mut u8) -> bool {
174+
let queue = unsafe { Queue::from_ptr(queue) };
175+
176+
unsafe { queue.try_receive(item) }
177+
}
178+
179+
fn messages_waiting(queue: QueuePtr) -> usize {
180+
let queue = unsafe { Queue::from_ptr(queue) };
181+
182+
queue.messages_waiting()
183+
}
184+
}
185+
186+
register_queue_implementation!(Queue);

esp-radio-preempt-driver/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#![no_std]
3030

3131
pub mod mutex;
32+
pub mod queue;
3233
pub mod semaphore;
3334

3435
use core::ffi::c_void;

0 commit comments

Comments
 (0)