mirror of
https://github.com/haileys/bark
synced 2024-11-10 14:04:15 +00:00
make bark-alloc fallible and add pbuf implementation
This commit is contained in:
parent
760e81ecf6
commit
422ce25c9f
11 changed files with 151 additions and 128 deletions
23
Cargo.lock
generated
23
Cargo.lock
generated
|
@ -88,7 +88,6 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bytemuck",
|
||||
"derive_more",
|
||||
"esp-alloc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -298,12 +297,6 @@ dependencies = [
|
|||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
|
||||
|
||||
[[package]]
|
||||
name = "dasp_sample"
|
||||
version = "0.11.0"
|
||||
|
@ -329,16 +322,6 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "esp-alloc"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83792eb7261a375bb838679fea2b45654b8f4a48da6bef10a96da5054aa81c7d"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"linked_list_allocator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
|
@ -476,12 +459,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked_list_allocator"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.10"
|
||||
|
|
|
@ -5,9 +5,8 @@ edition = "2021"
|
|||
|
||||
[features]
|
||||
alloc = ["bytemuck/extern_crate_alloc"]
|
||||
esp_alloc = ["esp-alloc"]
|
||||
pbuf = []
|
||||
|
||||
[dependencies]
|
||||
esp-alloc = { version = "0.3", optional = true }
|
||||
bytemuck = { workspace = true, optional = true }
|
||||
derive_more = { workspace = true }
|
||||
|
|
|
@ -8,7 +8,7 @@ use derive_more::{Deref, DerefMut};
|
|||
pub struct FixedBuffer<const N: usize>(alloc::boxed::Box<[u8]>);
|
||||
|
||||
impl<const N: usize> FixedBuffer<N> {
|
||||
pub fn alloc_zeroed() -> Self {
|
||||
FixedBuffer(bytemuck::allocation::zeroed_slice_box(N))
|
||||
pub fn alloc_zeroed() -> Result<Self, crate::AllocError> {
|
||||
Ok(FixedBuffer(bytemuck::allocation::zeroed_slice_box(N)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::ptr::null_mut;
|
||||
use core::slice;
|
||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||
|
||||
use esp_alloc::EspHeap;
|
||||
|
||||
static HEAP: AtomicPtr<EspHeap> = AtomicPtr::new(null_mut());
|
||||
|
||||
pub unsafe fn set_heap(heap: &'static EspHeap) {
|
||||
let result = HEAP.compare_exchange(
|
||||
null_mut(),
|
||||
heap as *const _ as *mut _,
|
||||
Ordering::SeqCst,
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
|
||||
if result.is_err() {
|
||||
panic!("bark_alloc: attempted to call set_heap twice");
|
||||
}
|
||||
}
|
||||
|
||||
fn heap() -> &'static EspHeap {
|
||||
let ptr = HEAP.load(Ordering::Relaxed);
|
||||
if ptr == null_mut() {
|
||||
panic!("bark_alloc: heap accessed before set! call set_heap first.")
|
||||
}
|
||||
|
||||
unsafe { &*(ptr as *const _) }
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct FixedBuffer<const N: usize>(*mut u8);
|
||||
|
||||
impl<const N: usize> FixedBuffer<N> {
|
||||
const LAYOUT: Layout = unsafe {
|
||||
// Layout::from_size_align is const but returns a Result,
|
||||
// we can't const unwrap results on stable rust yet.
|
||||
Layout::from_size_align_unchecked(N, 4)
|
||||
};
|
||||
|
||||
pub fn alloc_zeroed() -> Self {
|
||||
let ptr = unsafe { heap().alloc_zeroed(Self::LAYOUT) };
|
||||
if ptr == null_mut() {
|
||||
panic!("bark_alloc: allocation failed! requsted size: {N}");
|
||||
}
|
||||
|
||||
FixedBuffer(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Drop for FixedBuffer<N> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { heap().dealloc(self.0, Self::LAYOUT); }
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Deref for FixedBuffer<N> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(self.0, N) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> DerefMut for FixedBuffer<N> {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(self.0, N) }
|
||||
}
|
||||
}
|
|
@ -1,14 +1,19 @@
|
|||
#![no_std]
|
||||
|
||||
#[cfg(not(any(feature = "alloc", feature = "esp_alloc")))]
|
||||
#[cfg(not(any(feature = "alloc", feature = "pbuf")))]
|
||||
compile_error!("must enable alloc feature!");
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct AllocError {
|
||||
pub requested_bytes: usize
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[path = "alloc_box_impl.rs"]
|
||||
mod impl_;
|
||||
|
||||
#[cfg(feature = "esp_alloc")]
|
||||
#[path = "esp_alloc_impl.rs"]
|
||||
#[cfg(feature = "pbuf")]
|
||||
#[path = "pbuf_impl.rs"]
|
||||
mod impl_;
|
||||
|
||||
pub use impl_::*;
|
||||
|
|
101
bark-alloc/src/pbuf_impl.rs
Normal file
101
bark-alloc/src/pbuf_impl.rs
Normal file
|
@ -0,0 +1,101 @@
|
|||
use core::ops::{Deref, DerefMut};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use crate::AllocError;
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct FixedBuffer<const N: usize> {
|
||||
pbuf: NonNull<ffi::pbuf>,
|
||||
}
|
||||
|
||||
unsafe impl<const N: usize> Send for FixedBuffer<N> {}
|
||||
unsafe impl<const N: usize> Sync for FixedBuffer<N> {}
|
||||
|
||||
impl<const N: usize> FixedBuffer<N> {
|
||||
pub fn alloc_zeroed() -> Result<Self, AllocError> {
|
||||
let err = AllocError { requested_bytes: ffi::PBUF_TRANSPORT + N };
|
||||
let len = u16::try_from(N).map_err(|_| err)?;
|
||||
|
||||
// alloc the pbuf:
|
||||
let pbuf = unsafe {
|
||||
ffi::pbuf_alloc(ffi::PBUF_TRANSPORT as i32, len, ffi::PBUF_RAM)
|
||||
};
|
||||
|
||||
let mut pbuf = NonNull::new(pbuf).ok_or(err)?;
|
||||
|
||||
// zero its contents:
|
||||
unsafe {
|
||||
let payload = pbuf.as_mut().payload as *mut u8;
|
||||
core::ptr::write_bytes(payload, 0, N);
|
||||
}
|
||||
|
||||
Ok(FixedBuffer { pbuf })
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Deref for FixedBuffer<N> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
let pbuf = self.pbuf.as_ref();
|
||||
let payload = pbuf.payload as *mut u8 as *const u8;
|
||||
let len = usize::from(pbuf.len);
|
||||
core::slice::from_raw_parts(payload, len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> DerefMut for FixedBuffer<N> {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
unsafe {
|
||||
let pbuf = self.pbuf.as_mut();
|
||||
let payload = pbuf.payload as *mut u8;
|
||||
let len = usize::from(pbuf.len);
|
||||
core::slice::from_raw_parts_mut(payload, len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Drop for FixedBuffer<N> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ffi::pbuf_free(self.pbuf.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bindings to esp-lwip pbuf.h
|
||||
// https://github.com/espressif/esp-lwip/blob/7896c6cad020d17a986f7e850f603e084e319328/src/include/lwip/pbuf.h
|
||||
pub mod ffi {
|
||||
use core::ffi::c_void;
|
||||
|
||||
const PBUF_ALLOC_FLAG_DATA_CONTIGUOUS: i32 = 0x0200;
|
||||
const PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS: i32 = 0x80;
|
||||
const PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP: i32 = 0x00;
|
||||
|
||||
/// Downstream crates should statically assert that this is equal to or
|
||||
/// larger than their PBUF_TRANSPORT constant
|
||||
pub const PBUF_TRANSPORT: usize = 74;
|
||||
|
||||
/// Downstream crates should statically assert that this is equal to their
|
||||
/// PBUF_RAM constant
|
||||
pub const PBUF_RAM: i32 = PBUF_ALLOC_FLAG_DATA_CONTIGUOUS | PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS | PBUF_TYPE_ALLOC_SRC_MASK_STD_HEAP;
|
||||
|
||||
|
||||
#[repr(C)]
|
||||
pub struct pbuf {
|
||||
pub next: *mut pbuf,
|
||||
pub payload: *mut c_void,
|
||||
pub tot_len: u16,
|
||||
pub len: u16,
|
||||
pub type_internal: u8,
|
||||
pub flags: u8,
|
||||
// fields continue but this is all we need
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn pbuf_alloc(layer: i32, length: u16, type_: i32) -> *mut pbuf;
|
||||
pub fn pbuf_free(p: *mut pbuf) -> u8;
|
||||
}
|
||||
}
|
|
@ -12,6 +12,8 @@ use crate::time::SampleDuration;
|
|||
|
||||
use super::types::{AudioPacketHeader, StatsReplyFlags, SessionId};
|
||||
|
||||
pub use bark_alloc::AllocError;
|
||||
|
||||
pub const MAX_PACKET_SIZE: usize =
|
||||
size_of::<types::PacketHeader>() +
|
||||
size_of::<types::AudioPacketHeader>() +
|
||||
|
@ -29,11 +31,11 @@ impl Debug for PacketBuffer {
|
|||
}
|
||||
|
||||
impl PacketBuffer {
|
||||
pub fn allocate() -> Self {
|
||||
PacketBuffer {
|
||||
raw: bark_alloc::FixedBuffer::alloc_zeroed(),
|
||||
pub fn allocate() -> Result<Self, AllocError> {
|
||||
Ok(PacketBuffer {
|
||||
raw: bark_alloc::FixedBuffer::alloc_zeroed()?,
|
||||
len: 0,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
|
@ -61,11 +63,11 @@ impl PacketBuffer {
|
|||
pub struct Packet(PacketBuffer);
|
||||
|
||||
impl Packet {
|
||||
fn allocate(magic: Magic, len: usize) -> Self {
|
||||
let mut packet = Packet(PacketBuffer::allocate());
|
||||
fn allocate(magic: Magic, len: usize) -> Result<Self, AllocError> {
|
||||
let mut packet = Packet(PacketBuffer::allocate()?);
|
||||
packet.set_len(len);
|
||||
packet.header_mut().magic = magic;
|
||||
return packet;
|
||||
Ok(packet)
|
||||
}
|
||||
|
||||
pub fn from_buffer(buffer: PacketBuffer) -> Option<Packet> {
|
||||
|
@ -140,13 +142,13 @@ impl Audio {
|
|||
size_of::<types::AudioPacketHeader>() +
|
||||
size_of::<types::AudioPacketBuffer>();
|
||||
|
||||
pub fn write() -> AudioWriter {
|
||||
let packet = Packet::allocate(Magic::AUDIO, Self::LENGTH);
|
||||
pub fn write() -> Result<AudioWriter, AllocError> {
|
||||
let packet = Packet::allocate(Magic::AUDIO, Self::LENGTH)?;
|
||||
|
||||
AudioWriter {
|
||||
Ok(AudioWriter {
|
||||
packet: Audio(packet),
|
||||
written: SampleDuration::zero(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse(packet: Packet) -> Option<Self> {
|
||||
|
@ -253,8 +255,8 @@ impl Time {
|
|||
const DATA_RANGE: Range<usize> =
|
||||
0..size_of::<types::TimePacket>();
|
||||
|
||||
pub fn allocate() -> Self {
|
||||
Time(Packet::allocate(Magic::TIME, Self::LENGTH))
|
||||
pub fn allocate() -> Result<Self, AllocError> {
|
||||
Ok(Time(Packet::allocate(Magic::TIME, Self::LENGTH)?))
|
||||
}
|
||||
|
||||
pub fn parse(packet: Packet) -> Option<Self> {
|
||||
|
@ -288,8 +290,8 @@ impl Time {
|
|||
pub struct StatsRequest(Packet);
|
||||
|
||||
impl StatsRequest {
|
||||
pub fn new() -> Self {
|
||||
StatsRequest(Packet::allocate(Magic::STATS_REQ, 0))
|
||||
pub fn new() -> Result<Self, AllocError> {
|
||||
Ok(StatsRequest(Packet::allocate(Magic::STATS_REQ, 0)?))
|
||||
}
|
||||
|
||||
pub fn parse(packet: Packet) -> Option<Self> {
|
||||
|
@ -315,17 +317,17 @@ pub struct StatsReply(Packet);
|
|||
impl StatsReply {
|
||||
const LENGTH: usize = size_of::<types::StatsReplyPacket>();
|
||||
|
||||
fn new(flags: StatsReplyFlags, data: types::StatsReplyPacket) -> Self {
|
||||
let mut packet = Packet::allocate(Magic::STATS_REPLY, Self::LENGTH);
|
||||
fn new(flags: StatsReplyFlags, data: types::StatsReplyPacket) -> Result<Self, AllocError> {
|
||||
let mut packet = Packet::allocate(Magic::STATS_REPLY, Self::LENGTH)?;
|
||||
packet.header_mut().flags = bytemuck::cast(flags);
|
||||
|
||||
let mut reply = StatsReply(packet);
|
||||
*reply.data_mut() = data;
|
||||
|
||||
reply
|
||||
Ok(reply)
|
||||
}
|
||||
|
||||
pub fn source(sid: SessionId, node: NodeStats) -> Self {
|
||||
pub fn source(sid: SessionId, node: NodeStats) -> Result<Self, AllocError> {
|
||||
let receiver = ReceiverStats::zeroed();
|
||||
|
||||
Self::new(
|
||||
|
@ -334,7 +336,7 @@ impl StatsReply {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn receiver(sid: SessionId, receiver: ReceiverStats, node: NodeStats) -> Self {
|
||||
pub fn receiver(sid: SessionId, receiver: ReceiverStats, node: NodeStats) -> Result<Self, AllocError> {
|
||||
Self::new(
|
||||
StatsReplyFlags::IS_RECEIVER,
|
||||
types::StatsReplyPacket { sid, receiver, node },
|
||||
|
|
|
@ -576,7 +576,9 @@ pub fn run(opt: ReceiveOpt) -> Result<(), RunError> {
|
|||
let receiver = *state.recv.stats();
|
||||
drop(state);
|
||||
|
||||
let reply = StatsReply::receiver(sid, receiver, node);
|
||||
let reply = StatsReply::receiver(sid, receiver, node)
|
||||
.expect("allocate StatsReply packet");
|
||||
|
||||
let _ = protocol.send_to(reply.as_packet(), peer);
|
||||
}
|
||||
Some(PacketKind::StatsReply(_)) => {
|
||||
|
|
|
@ -138,7 +138,8 @@ impl ProtocolSocket {
|
|||
|
||||
pub fn recv_from(&self) -> Result<(Packet, PeerId), io::Error> {
|
||||
loop {
|
||||
let mut buffer = PacketBuffer::allocate();
|
||||
let mut buffer = PacketBuffer::allocate()
|
||||
.expect("allocate PacketBuffer");
|
||||
|
||||
let (nbytes, peer) = self.socket.recv_from(buffer.as_full_buffer_mut())?;
|
||||
buffer.set_len(nbytes);
|
||||
|
|
|
@ -33,7 +33,9 @@ pub fn run(opt: StatsOpt) -> Result<(), RunError> {
|
|||
std::thread::spawn({
|
||||
let protocol = Arc::clone(&protocol);
|
||||
move || {
|
||||
let request = StatsRequest::new();
|
||||
let request = StatsRequest::new()
|
||||
.expect("allocate StatsRequest packet");
|
||||
|
||||
loop {
|
||||
let _ = protocol.broadcast(request.as_packet());
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
|
|
|
@ -62,7 +62,8 @@ pub fn run(opt: StreamOpt) -> Result<(), RunError> {
|
|||
dts: TimestampMicros(0),
|
||||
};
|
||||
|
||||
let mut audio_buffer = Audio::write();
|
||||
let mut audio_buffer = Audio::write()
|
||||
.expect("allocate Audio packet");
|
||||
|
||||
let stream = device.build_input_stream(&config,
|
||||
{
|
||||
|
@ -95,7 +96,8 @@ pub fn run(opt: StreamOpt) -> Result<(), RunError> {
|
|||
// if packet buffer is full, finalize it and send off the packet:
|
||||
if audio_buffer.valid_length() {
|
||||
// take packet writer and replace with new
|
||||
let audio = std::mem::replace(&mut audio_buffer, Audio::write());
|
||||
let audio = std::mem::replace(&mut audio_buffer,
|
||||
Audio::write().expect("allocate Audio packet"));
|
||||
|
||||
// finalize packet
|
||||
let audio_packet = audio.finalize(AudioPacketHeader {
|
||||
|
@ -134,7 +136,8 @@ pub fn run(opt: StreamOpt) -> Result<(), RunError> {
|
|||
|
||||
let protocol = Arc::clone(&protocol);
|
||||
move || {
|
||||
let mut time = packet::Time::allocate();
|
||||
let mut time = packet::Time::allocate()
|
||||
.expect("allocate Time packet");
|
||||
|
||||
// set up packet
|
||||
let data = time.data_mut();
|
||||
|
@ -190,7 +193,9 @@ pub fn run(opt: StreamOpt) -> Result<(), RunError> {
|
|||
|
||||
}
|
||||
Some(PacketKind::StatsRequest(_)) => {
|
||||
let reply = StatsReply::source(sid, node);
|
||||
let reply = StatsReply::source(sid, node)
|
||||
.expect("allocate StatsReply packet");
|
||||
|
||||
let _ = protocol.send_to(reply.as_packet(), peer);
|
||||
}
|
||||
Some(PacketKind::StatsReply(_)) => {
|
||||
|
|
Loading…
Reference in a new issue