Heap-allocated packets not necessary; no_std and no-alloc build supported end-to-end
This commit is contained in:
parent
8b3bb9527c
commit
7ef7e93eb4
12 changed files with 14 additions and 333 deletions
|
@ -1,4 +1,4 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["matter", "matter_macro_derive", "boxslab", "tools/tlv_tool"]
|
members = ["matter", "matter_macro_derive", "tools/tlv_tool"]
|
||||||
|
|
||||||
exclude = ["examples/*"]
|
exclude = ["examples/*"]
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "boxslab"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bitmaps={version="3.2.0", features=[]}
|
|
|
@ -1,237 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020-2022 Project CHIP Authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
mem::MaybeUninit,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
sync::Mutex,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: why is max bitmap size 64 a correct max size? Could we match
|
|
||||||
// boxslabs instead or store used/not used inside the box slabs themselves?
|
|
||||||
const MAX_BITMAP_SIZE: usize = 64;
|
|
||||||
pub struct Bitmap {
|
|
||||||
inner: bitmaps::Bitmap<MAX_BITMAP_SIZE>,
|
|
||||||
max_size: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bitmap {
|
|
||||||
pub fn new(max_size: usize) -> Self {
|
|
||||||
assert!(max_size <= MAX_BITMAP_SIZE);
|
|
||||||
Bitmap {
|
|
||||||
inner: bitmaps::Bitmap::new(),
|
|
||||||
max_size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(&mut self, index: usize) -> bool {
|
|
||||||
assert!(index < self.max_size);
|
|
||||||
self.inner.set(index, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self, index: usize) -> bool {
|
|
||||||
assert!(index < self.max_size);
|
|
||||||
self.inner.set(index, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn first_false_index(&self) -> Option<usize> {
|
|
||||||
match self.inner.first_false_index() {
|
|
||||||
Some(idx) if idx < self.max_size => Some(idx),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.inner.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_full(&self) -> bool {
|
|
||||||
self.first_false_index().is_none()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! box_slab {
|
|
||||||
($name:ident,$t:ty,$v:expr) => {
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
use std::sync::Once;
|
|
||||||
use $crate::{BoxSlab, Slab, SlabPool};
|
|
||||||
|
|
||||||
pub struct $name;
|
|
||||||
|
|
||||||
impl SlabPool for $name {
|
|
||||||
type SlabType = $t;
|
|
||||||
fn get_slab() -> &'static Slab<Self> {
|
|
||||||
const MAYBE_INIT: MaybeUninit<$t> = MaybeUninit::uninit();
|
|
||||||
static mut SLAB_POOL: [MaybeUninit<$t>; $v] = [MAYBE_INIT; $v];
|
|
||||||
static mut SLAB_SPACE: Option<Slab<$name>> = None;
|
|
||||||
static mut INIT: Once = Once::new();
|
|
||||||
unsafe {
|
|
||||||
INIT.call_once(|| {
|
|
||||||
SLAB_SPACE = Some(Slab::<$name>::init(&mut SLAB_POOL, $v));
|
|
||||||
});
|
|
||||||
SLAB_SPACE.as_ref().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait SlabPool {
|
|
||||||
type SlabType: 'static;
|
|
||||||
fn get_slab() -> &'static Slab<Self>
|
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Inner<T: 'static + SlabPool> {
|
|
||||||
pool: &'static mut [MaybeUninit<T::SlabType>],
|
|
||||||
map: Bitmap,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Instead of a mutex, we should replace this with a CAS loop
|
|
||||||
pub struct Slab<T: 'static + SlabPool>(Mutex<Inner<T>>);
|
|
||||||
|
|
||||||
impl<T: SlabPool> Slab<T> {
|
|
||||||
pub fn init(pool: &'static mut [MaybeUninit<T::SlabType>], size: usize) -> Self {
|
|
||||||
Self(Mutex::new(Inner {
|
|
||||||
pool,
|
|
||||||
map: Bitmap::new(size),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_new(new_object: T::SlabType) -> Option<BoxSlab<T>> {
|
|
||||||
let slab = T::get_slab();
|
|
||||||
let mut inner = slab.0.lock().unwrap();
|
|
||||||
if let Some(index) = inner.map.first_false_index() {
|
|
||||||
inner.map.set(index);
|
|
||||||
inner.pool[index].write(new_object);
|
|
||||||
let cell_ptr = unsafe { &mut *inner.pool[index].as_mut_ptr() };
|
|
||||||
Some(BoxSlab {
|
|
||||||
data: cell_ptr,
|
|
||||||
index,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn free(&self, index: usize) {
|
|
||||||
let mut inner = self.0.lock().unwrap();
|
|
||||||
inner.map.reset(index);
|
|
||||||
let old_value = std::mem::replace(&mut inner.pool[index], MaybeUninit::uninit());
|
|
||||||
let _old_value = unsafe { old_value.assume_init() };
|
|
||||||
// This will drop the old_value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BoxSlab<T: 'static + SlabPool> {
|
|
||||||
// Because the data is a reference within the MaybeUninit, we don't have a mechanism
|
|
||||||
// to go out to the MaybeUninit from this reference. Hence this index
|
|
||||||
index: usize,
|
|
||||||
// TODO: We should figure out a way to get rid of the index too
|
|
||||||
data: &'static mut T::SlabType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static + SlabPool> Drop for BoxSlab<T> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
T::get_slab().free(self.index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: SlabPool> Deref for BoxSlab<T> {
|
|
||||||
type Target = T::SlabType;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: SlabPool> DerefMut for BoxSlab<T> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
self.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use std::{ops::Deref, sync::Arc};
|
|
||||||
|
|
||||||
pub struct Test {
|
|
||||||
val: Arc<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
box_slab!(TestSlab, Test, 3);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn simple_alloc_free() {
|
|
||||||
{
|
|
||||||
let a = Slab::<TestSlab>::try_new(Test { val: Arc::new(10) }).unwrap();
|
|
||||||
assert_eq!(*a.val.deref(), 10);
|
|
||||||
let inner = TestSlab::get_slab().0.lock().unwrap();
|
|
||||||
assert!(!inner.map.is_empty());
|
|
||||||
}
|
|
||||||
// Validates that the 'Drop' got executed
|
|
||||||
let inner = TestSlab::get_slab().0.lock().unwrap();
|
|
||||||
assert!(inner.map.is_empty());
|
|
||||||
println!("Box Size {}", std::mem::size_of::<Box<Test>>());
|
|
||||||
println!("BoxSlab Size {}", std::mem::size_of::<BoxSlab<TestSlab>>());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alloc_full_block() {
|
|
||||||
{
|
|
||||||
let a = Slab::<TestSlab>::try_new(Test { val: Arc::new(10) }).unwrap();
|
|
||||||
let b = Slab::<TestSlab>::try_new(Test { val: Arc::new(11) }).unwrap();
|
|
||||||
let c = Slab::<TestSlab>::try_new(Test { val: Arc::new(12) }).unwrap();
|
|
||||||
// Test that at overflow, we return None
|
|
||||||
assert!(Slab::<TestSlab>::try_new(Test { val: Arc::new(13) }).is_none(),);
|
|
||||||
assert_eq!(*b.val.deref(), 11);
|
|
||||||
|
|
||||||
{
|
|
||||||
let inner = TestSlab::get_slab().0.lock().unwrap();
|
|
||||||
// Test that the bitmap is marked as full
|
|
||||||
assert!(inner.map.is_full());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Purposefully drop, to test that new allocation is possible
|
|
||||||
std::mem::drop(b);
|
|
||||||
let d = Slab::<TestSlab>::try_new(Test { val: Arc::new(21) }).unwrap();
|
|
||||||
assert_eq!(*d.val.deref(), 21);
|
|
||||||
|
|
||||||
// Ensure older allocations are still valid
|
|
||||||
assert_eq!(*a.val.deref(), 10);
|
|
||||||
assert_eq!(*c.val.deref(), 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validates that the 'Drop' got executed - test that the bitmap is empty
|
|
||||||
let inner = TestSlab::get_slab().0.lock().unwrap();
|
|
||||||
assert!(inner.map.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_drop_logic() {
|
|
||||||
let root = Arc::new(10);
|
|
||||||
{
|
|
||||||
let _a = Slab::<TestSlab>::try_new(Test { val: root.clone() }).unwrap();
|
|
||||||
let _b = Slab::<TestSlab>::try_new(Test { val: root.clone() }).unwrap();
|
|
||||||
let _c = Slab::<TestSlab>::try_new(Test { val: root.clone() }).unwrap();
|
|
||||||
assert_eq!(Arc::strong_count(&root), 4);
|
|
||||||
}
|
|
||||||
// Test that Drop was correctly called on all the members of the pool
|
|
||||||
assert_eq!(Arc::strong_count(&root), 1);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -51,7 +51,7 @@ fn main() {
|
||||||
//let mut mdns = matter::mdns::astro::AstroMdns::new().unwrap();
|
//let mut mdns = matter::mdns::astro::AstroMdns::new().unwrap();
|
||||||
let mut mdns = matter::mdns::libmdns::LibMdns::new().unwrap();
|
let mut mdns = matter::mdns::libmdns::LibMdns::new().unwrap();
|
||||||
|
|
||||||
let matter = Matter::new_default(&dev_info, &mut mdns);
|
let matter = Matter::new_default(&dev_info, &mut mdns, matter::transport::udp::MATTER_PORT);
|
||||||
|
|
||||||
let dev_att = dev_att::HardCodedDevAtt::new();
|
let dev_att = dev_att::HardCodedDevAtt::new();
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ crypto_esp_mbedtls = ["esp-idf-sys"]
|
||||||
crypto_rustcrypto = ["sha2", "hmac", "pbkdf2", "hkdf", "aes", "ccm", "p256", "elliptic-curve", "crypto-bigint", "x509-cert"]
|
crypto_rustcrypto = ["sha2", "hmac", "pbkdf2", "hkdf", "aes", "ccm", "p256", "elliptic-curve", "crypto-bigint", "x509-cert"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
boxslab = { path = "../boxslab" }
|
|
||||||
matter_macro_derive = { path = "../matter_macro_derive" }
|
matter_macro_derive = { path = "../matter_macro_derive" }
|
||||||
bitflags = "1.3"
|
bitflags = "1.3"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
|
@ -35,6 +34,7 @@ num-derive = "0.3.3"
|
||||||
num-traits = "0.2.15"
|
num-traits = "0.2.15"
|
||||||
strum = { version = "0.24", features = ["derive"], default-features = false, no-default-feature = true }
|
strum = { version = "0.24", features = ["derive"], default-features = false, no-default-feature = true }
|
||||||
log = { version = "0.4.17", features = ["max_level_debug", "release_max_level_debug"] }
|
log = { version = "0.4.17", features = ["max_level_debug", "release_max_level_debug"] }
|
||||||
|
no-std-net = "0.6"
|
||||||
subtle = "2.4.1"
|
subtle = "2.4.1"
|
||||||
safemem = "0.3.3"
|
safemem = "0.3.3"
|
||||||
colored = "2.0.0" # TODO: Requires STD
|
colored = "2.0.0" # TODO: Requires STD
|
||||||
|
|
|
@ -25,7 +25,6 @@ use crate::{
|
||||||
mdns::{Mdns, MdnsMgr},
|
mdns::{Mdns, MdnsMgr},
|
||||||
pairing::{print_pairing_code_and_qr, DiscoveryCapabilities},
|
pairing::{print_pairing_code_and_qr, DiscoveryCapabilities},
|
||||||
secure_channel::{pake::PaseMgr, spake2p::VerifierData},
|
secure_channel::{pake::PaseMgr, spake2p::VerifierData},
|
||||||
transport::udp::MATTER_PORT,
|
|
||||||
utils::{
|
utils::{
|
||||||
epoch::{Epoch, UtcCalendar},
|
epoch::{Epoch, UtcCalendar},
|
||||||
rand::Rand,
|
rand::Rand,
|
||||||
|
@ -55,11 +54,11 @@ pub struct Matter<'a> {
|
||||||
|
|
||||||
impl<'a> Matter<'a> {
|
impl<'a> Matter<'a> {
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn new_default(dev_det: &'a BasicInfoConfig, mdns: &'a mut dyn Mdns) -> Self {
|
pub fn new_default(dev_det: &'a BasicInfoConfig, mdns: &'a mut dyn Mdns, port: u16) -> Self {
|
||||||
use crate::utils::epoch::{sys_epoch, sys_utc_calendar};
|
use crate::utils::epoch::{sys_epoch, sys_utc_calendar};
|
||||||
use crate::utils::rand::sys_rand;
|
use crate::utils::rand::sys_rand;
|
||||||
|
|
||||||
Self::new(dev_det, mdns, sys_epoch, sys_rand, sys_utc_calendar)
|
Self::new(dev_det, mdns, sys_epoch, sys_rand, sys_utc_calendar, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new Matter object
|
/// Creates a new Matter object
|
||||||
|
@ -74,6 +73,7 @@ impl<'a> Matter<'a> {
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
rand: Rand,
|
rand: Rand,
|
||||||
utc_calendar: UtcCalendar,
|
utc_calendar: UtcCalendar,
|
||||||
|
port: u16,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
fabric_mgr: RefCell::new(FabricMgr::new()),
|
fabric_mgr: RefCell::new(FabricMgr::new()),
|
||||||
|
@ -84,7 +84,7 @@ impl<'a> Matter<'a> {
|
||||||
dev_det.vid,
|
dev_det.vid,
|
||||||
dev_det.pid,
|
dev_det.pid,
|
||||||
dev_det.device_name,
|
dev_det.device_name,
|
||||||
MATTER_PORT,
|
port,
|
||||||
mdns,
|
mdns,
|
||||||
)),
|
)),
|
||||||
epoch,
|
epoch,
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
|
|
||||||
use core::{array::TryFromSliceError, fmt, str::Utf8Error};
|
use core::{array::TryFromSliceError, fmt, str::Utf8Error};
|
||||||
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
AttributeNotFound,
|
AttributeNotFound,
|
||||||
|
@ -122,7 +120,7 @@ impl<T> From<std::sync::PoisonError<T>> for Error {
|
||||||
#[cfg(feature = "crypto_openssl")]
|
#[cfg(feature = "crypto_openssl")]
|
||||||
impl From<openssl::error::ErrorStack> for Error {
|
impl From<openssl::error::ErrorStack> for Error {
|
||||||
fn from(e: openssl::error::ErrorStack) -> Self {
|
fn from(e: openssl::error::ErrorStack) -> Self {
|
||||||
error!("Error in TLS: {}", e);
|
::log::error!("Error in TLS: {}", e);
|
||||||
Self::TLSStack
|
Self::TLSStack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +128,7 @@ impl From<openssl::error::ErrorStack> for Error {
|
||||||
#[cfg(feature = "crypto_mbedtls")]
|
#[cfg(feature = "crypto_mbedtls")]
|
||||||
impl From<mbedtls::Error> for Error {
|
impl From<mbedtls::Error> for Error {
|
||||||
fn from(e: mbedtls::Error) -> Self {
|
fn from(e: mbedtls::Error) -> Self {
|
||||||
error!("Error in TLS: {}", e);
|
::log::error!("Error in TLS: {}", e);
|
||||||
Self::TLSStack
|
Self::TLSStack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,6 @@ pub mod mdns;
|
||||||
pub mod pairing;
|
pub mod pairing;
|
||||||
pub mod persist;
|
pub mod persist;
|
||||||
pub mod secure_channel;
|
pub mod secure_channel;
|
||||||
pub mod sys;
|
|
||||||
pub mod tlv;
|
pub mod tlv;
|
||||||
pub mod transport;
|
pub mod transport;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020-2022 Project CHIP Authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// The Packet Pool that is allocated from. POSIX systems can use
|
|
||||||
// higher values unlike embedded systems
|
|
||||||
pub const MAX_PACKET_POOL_SIZE: usize = 25;
|
|
|
@ -25,4 +25,5 @@ pub mod plain_hdr;
|
||||||
pub mod proto_ctx;
|
pub mod proto_ctx;
|
||||||
pub mod proto_hdr;
|
pub mod proto_hdr;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
pub mod udp;
|
pub mod udp;
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use core::fmt::{Debug, Display};
|
use core::fmt::{Debug, Display};
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
use no_std_net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
|
#[cfg(feature = "std")]
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
|
|
|
@ -15,14 +15,10 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use log::{error, trace};
|
use log::error;
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
use boxslab::box_slab;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::Error,
|
error::Error,
|
||||||
sys::MAX_PACKET_POOL_SIZE,
|
|
||||||
utils::{parsebuf::ParseBuf, writebuf::WriteBuf},
|
utils::{parsebuf::ParseBuf, writebuf::WriteBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,54 +30,6 @@ use super::{
|
||||||
|
|
||||||
pub const MAX_RX_BUF_SIZE: usize = 1583;
|
pub const MAX_RX_BUF_SIZE: usize = 1583;
|
||||||
pub const MAX_TX_BUF_SIZE: usize = 1280 - 40/*IPV6 header size*/ - 8/*UDP header size*/;
|
pub const MAX_TX_BUF_SIZE: usize = 1280 - 40/*IPV6 header size*/ - 8/*UDP header size*/;
|
||||||
type Buffer = [u8; MAX_RX_BUF_SIZE];
|
|
||||||
|
|
||||||
// TODO: I am not very happy with this construction, need to find another way to do this
|
|
||||||
pub struct BufferPool {
|
|
||||||
buffers: [Option<Buffer>; MAX_PACKET_POOL_SIZE],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BufferPool {
|
|
||||||
const INIT: Option<Buffer> = None;
|
|
||||||
fn get() -> &'static Mutex<BufferPool> {
|
|
||||||
static mut BUFFER_HOLDER: Option<Mutex<BufferPool>> = None;
|
|
||||||
static ONCE: Once = Once::new();
|
|
||||||
unsafe {
|
|
||||||
ONCE.call_once(|| {
|
|
||||||
BUFFER_HOLDER = Some(Mutex::new(BufferPool {
|
|
||||||
buffers: [BufferPool::INIT; MAX_PACKET_POOL_SIZE],
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
BUFFER_HOLDER.as_ref().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc() -> Option<(usize, &'static mut Buffer)> {
|
|
||||||
trace!("Buffer Alloc called\n");
|
|
||||||
|
|
||||||
let mut pool = BufferPool::get().lock().unwrap();
|
|
||||||
for i in 0..MAX_PACKET_POOL_SIZE {
|
|
||||||
if pool.buffers[i].is_none() {
|
|
||||||
pool.buffers[i] = Some([0; MAX_RX_BUF_SIZE]);
|
|
||||||
// Sigh! to by-pass the borrow-checker telling us we are stealing a mutable reference
|
|
||||||
// from under the lock
|
|
||||||
// In this case the lock only protects against the setting of Some/None,
|
|
||||||
// the objects then are independently accessed in a unique way
|
|
||||||
let buffer = unsafe { &mut *(pool.buffers[i].as_mut().unwrap() as *mut Buffer) };
|
|
||||||
return Some((i, buffer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn free(index: usize) {
|
|
||||||
trace!("Buffer Free called\n");
|
|
||||||
let mut pool = BufferPool::get().lock().unwrap();
|
|
||||||
if pool.buffers[index].is_some() {
|
|
||||||
pool.buffers[index] = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
enum RxState {
|
enum RxState {
|
||||||
|
@ -229,5 +177,3 @@ impl<'a> Packet<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
box_slab!(PacketPool, Packet<'static>, MAX_PACKET_POOL_SIZE);
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue