Skip to content

Commit 0d79d7a

Browse files
committed
Reduce stack-allocations (esp-rs#243)
* Reduce stack-allocations * Avoid explicit panic on exhausted backing memory * Remove unnecessary `transmute`
1 parent 182c82e commit 0d79d7a

File tree

2 files changed

+87
-28
lines changed

2 files changed

+87
-28
lines changed

esp-wifi/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,9 @@ pub fn initialize(
277277
rom_ets_update_cpu_frequency(240); // we know it's 240MHz because of the check above
278278
}
279279

280+
#[cfg(feature = "wifi")]
281+
crate::wifi::DataFrame::internal_init();
282+
280283
log::info!("esp-wifi configuration {:?}", crate::CONFIG);
281284

282285
crate::common_adapter::chip_specific::enable_wifi_power_domain();

esp-wifi/src/wifi/mod.rs

Lines changed: 84 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#[doc(hidden)]
22
pub mod os_adapter;
33

4-
use core::{cell::RefCell, marker::PhantomData, mem::MaybeUninit};
4+
use core::{cell::RefCell, mem::MaybeUninit};
55

66
use crate::common_adapter::*;
77
use crate::EspWifiInitialization;
@@ -31,6 +31,7 @@ use esp_wifi_sys::include::wifi_interface_t_WIFI_IF_AP;
3131
use esp_wifi_sys::include::wifi_mode_t_WIFI_MODE_AP;
3232
use esp_wifi_sys::include::wifi_mode_t_WIFI_MODE_APSTA;
3333
use esp_wifi_sys::include::wifi_mode_t_WIFI_MODE_NULL;
34+
use heapless::Vec;
3435
use num_derive::FromPrimitive;
3536
use num_traits::FromPrimitive;
3637

@@ -97,31 +98,72 @@ impl WifiMode {
9798
}
9899
}
99100

101+
const DATA_FRAMES_MAX_COUNT: usize = RX_QUEUE_SIZE + RX_QUEUE_SIZE;
102+
const DATA_FRAME_SIZE: usize = MTU + ETHERNET_FRAME_HEADER_SIZE;
103+
104+
static mut DATA_FRAME_BACKING_MEMORY: MaybeUninit<[u8; DATA_FRAMES_MAX_COUNT * DATA_FRAME_SIZE]> =
105+
MaybeUninit::uninit();
106+
107+
static DATA_FRAME_BACKING_MEMORY_FREE_SLOTS: Mutex<RefCell<Vec<usize, DATA_FRAMES_MAX_COUNT>>> =
108+
Mutex::new(RefCell::new(Vec::new()));
109+
100110
#[derive(Debug, Clone, Copy)]
101-
pub(crate) struct DataFrame<'a> {
111+
pub(crate) struct DataFrame {
102112
len: usize,
103-
data: [u8; MTU + ETHERNET_FRAME_HEADER_SIZE],
104-
_phantom: PhantomData<&'a ()>,
113+
index: usize,
105114
}
106115

107-
impl<'a> DataFrame<'a> {
108-
pub(crate) fn new() -> DataFrame<'a> {
109-
DataFrame {
110-
len: 0,
111-
data: [0u8; MTU + ETHERNET_FRAME_HEADER_SIZE],
112-
_phantom: Default::default(),
116+
impl DataFrame {
117+
pub(crate) fn internal_init() {
118+
critical_section::with(|cs| {
119+
let mut free_slots = DATA_FRAME_BACKING_MEMORY_FREE_SLOTS.borrow_ref_mut(cs);
120+
for i in 0..DATA_FRAMES_MAX_COUNT {
121+
free_slots.push(i).unwrap();
122+
}
123+
});
124+
}
125+
126+
pub(crate) fn new() -> Option<DataFrame> {
127+
let index = critical_section::with(|cs| {
128+
DATA_FRAME_BACKING_MEMORY_FREE_SLOTS
129+
.borrow_ref_mut(cs)
130+
.pop()
131+
});
132+
133+
match index {
134+
Some(index) => Some(DataFrame { len: 0, index }),
135+
None => None,
113136
}
114137
}
115138

116-
pub(crate) fn from_bytes(bytes: &[u8]) -> DataFrame {
117-
let mut data = DataFrame::new();
139+
pub(crate) fn free(self) {
140+
critical_section::with(|cs| {
141+
let mut free_slots = DATA_FRAME_BACKING_MEMORY_FREE_SLOTS.borrow_ref_mut(cs);
142+
free_slots.push(self.index).unwrap();
143+
});
144+
}
145+
146+
pub(crate) fn data_mut(&mut self) -> &mut [u8] {
147+
let data = unsafe { DATA_FRAME_BACKING_MEMORY.assume_init_mut() };
148+
&mut data[(self.index * DATA_FRAME_SIZE)..][..DATA_FRAME_SIZE]
149+
}
150+
151+
pub(crate) fn from_bytes(bytes: &[u8]) -> Option<DataFrame> {
152+
let mut data = DataFrame::new()?;
118153
data.len = bytes.len();
119-
data.data[..bytes.len()].copy_from_slice(bytes);
120-
data
154+
let mem = unsafe { DATA_FRAME_BACKING_MEMORY.assume_init_mut() };
155+
let len = usize::min(bytes.len(), DATA_FRAME_SIZE);
156+
if len != bytes.len() {
157+
log::warn!("Trying to store more data than available into DataFrame. Check MTU");
158+
}
159+
160+
mem[(data.index * DATA_FRAME_SIZE)..][..len].copy_from_slice(bytes);
161+
Some(data)
121162
}
122163

123-
pub(crate) fn slice(&'a self) -> &'a [u8] {
124-
&self.data[..self.len]
164+
pub(crate) fn slice(&self) -> &[u8] {
165+
let data = unsafe { DATA_FRAME_BACKING_MEMORY.assume_init_ref() };
166+
&data[(self.index * DATA_FRAME_SIZE)..][..self.len]
125167
}
126168
}
127169

@@ -609,7 +651,11 @@ unsafe extern "C" fn recv_cb(
609651
eb: *mut crate::binary::c_types::c_void,
610652
) -> esp_err_t {
611653
let src = core::slice::from_raw_parts_mut(buffer as *mut u8, len as usize);
612-
let packet = DataFrame::from_bytes(src);
654+
let packet = if let Some(packet) = DataFrame::from_bytes(src) {
655+
packet
656+
} else {
657+
return esp_wifi_sys::include::ESP_ERR_NO_MEM as esp_err_t;
658+
};
613659

614660
let res = critical_section::with(|cs| {
615661
let mut queue = DATA_QUEUE_RX.borrow_ref_mut(cs);
@@ -621,10 +667,12 @@ unsafe extern "C" fn recv_cb(
621667

622668
0
623669
} else {
670+
packet.free();
624671
log::error!("RX QUEUE FULL");
625672
1
626673
}
627674
});
675+
628676
esp_wifi_internal_free_rx_buffer(eb);
629677

630678
res
@@ -978,9 +1026,12 @@ impl RxToken for WifiRxToken {
9781026
let mut data = queue
9791027
.dequeue()
9801028
.expect("unreachable: transmit()/receive() ensures there is a packet to process");
981-
let buffer = unsafe { core::slice::from_raw_parts(&data.data as *const u8, data.len) };
1029+
let len = data.len;
1030+
let buffer = &mut data.data_mut()[..len];
9821031
dump_packet_info(&buffer);
983-
f(&mut data.data[..])
1032+
let res = f(buffer);
1033+
data.free();
1034+
res
9841035
})
9851036
}
9861037
}
@@ -996,9 +1047,9 @@ impl TxToken for WifiTxToken {
9961047
let res = critical_section::with(|cs| {
9971048
let mut queue = DATA_QUEUE_TX.borrow_ref_mut(cs);
9981049

999-
let mut packet = DataFrame::new();
1050+
let mut packet = DataFrame::new().expect("unreachable: transmit()/receive() ensures there is a buffer free (which means we also have free buffer space)");
10001051
packet.len = len;
1001-
let res = f(&mut packet.data[..len]);
1052+
let res = f(&mut packet.data_mut()[..len]);
10021053
queue
10031054
.enqueue(packet)
10041055
.expect("unreachable: transmit()/receive() ensures there is a buffer free");
@@ -1024,7 +1075,7 @@ pub fn send_data_if_needed() {
10241075
wifi_mode_t_WIFI_MODE_AP | wifi_mode_t_WIFI_MODE_APSTA
10251076
);
10261077

1027-
while let Some(packet) = queue.dequeue() {
1078+
while let Some(mut packet) = queue.dequeue() {
10281079
log::trace!("sending... {} bytes", packet.len);
10291080
dump_packet_info(packet.slice());
10301081

@@ -1037,7 +1088,7 @@ pub fn send_data_if_needed() {
10371088
unsafe {
10381089
let _res = esp_wifi_internal_tx(
10391090
interface,
1040-
&packet.data as *const _ as *mut crate::binary::c_types::c_void,
1091+
packet.data_mut() as *const _ as *mut crate::binary::c_types::c_void,
10411092
packet.len as u16,
10421093
);
10431094
if _res != 0 {
@@ -1047,6 +1098,8 @@ pub fn send_data_if_needed() {
10471098
}
10481099
#[cfg(feature = "embassy-net")]
10491100
embassy::TRANSMIT_WAKER.wake();
1101+
1102+
packet.free();
10501103
}
10511104
});
10521105
}
@@ -1287,10 +1340,12 @@ pub(crate) mod embassy {
12871340
let mut data = queue.dequeue().expect(
12881341
"unreachable: transmit()/receive() ensures there is a packet to process",
12891342
);
1290-
let buffer =
1291-
unsafe { core::slice::from_raw_parts(&data.data as *const u8, data.len) };
1343+
let len = data.len;
1344+
let buffer = &mut data.data_mut()[..len];
12921345
dump_packet_info(&buffer);
1293-
f(&mut data.data[..])
1346+
let res = f(buffer);
1347+
data.free();
1348+
res
12941349
})
12951350
}
12961351
}
@@ -1303,9 +1358,10 @@ pub(crate) mod embassy {
13031358
let res = critical_section::with(|cs| {
13041359
let mut queue = DATA_QUEUE_TX.borrow_ref_mut(cs);
13051360

1306-
let mut packet = DataFrame::new();
1361+
let mut packet = DataFrame::new().expect("unreachable: transmit()/receive() ensures there is a buffer free and space available");
1362+
13071363
packet.len = len;
1308-
let res = f(&mut packet.data[..len]);
1364+
let res = f(&mut packet.data_mut()[..len]);
13091365
queue
13101366
.enqueue(packet)
13111367
.expect("unreachable: transmit()/receive() ensures there is a buffer free");

0 commit comments

Comments
 (0)