diff --git a/Cargo.lock b/Cargo.lock index e8c8c3c..ecfe9ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/bark-alloc/Cargo.toml b/bark-alloc/Cargo.toml index 4647cf6..ad5b92f 100644 --- a/bark-alloc/Cargo.toml +++ b/bark-alloc/Cargo.toml @@ -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 } diff --git a/bark-alloc/src/alloc_box_impl.rs b/bark-alloc/src/alloc_box_impl.rs index 333f403..aeaf603 100644 --- a/bark-alloc/src/alloc_box_impl.rs +++ b/bark-alloc/src/alloc_box_impl.rs @@ -8,7 +8,7 @@ use derive_more::{Deref, DerefMut}; pub struct FixedBuffer(alloc::boxed::Box<[u8]>); impl FixedBuffer { - pub fn alloc_zeroed() -> Self { - FixedBuffer(bytemuck::allocation::zeroed_slice_box(N)) + pub fn alloc_zeroed() -> Result { + Ok(FixedBuffer(bytemuck::allocation::zeroed_slice_box(N))) } } diff --git a/bark-alloc/src/esp_alloc_impl.rs b/bark-alloc/src/esp_alloc_impl.rs deleted file mode 100644 index fb38729..0000000 --- a/bark-alloc/src/esp_alloc_impl.rs +++ /dev/null @@ -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 = 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(*mut u8); - -impl FixedBuffer { - 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 Drop for FixedBuffer { - fn drop(&mut self) { - unsafe { heap().dealloc(self.0, Self::LAYOUT); } - } -} - -impl Deref for FixedBuffer { - type Target = [u8]; - - fn deref(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.0, N) } - } -} - -impl DerefMut for FixedBuffer { - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.0, N) } - } -} diff --git a/bark-alloc/src/lib.rs b/bark-alloc/src/lib.rs index d0bc564..03147d2 100644 --- a/bark-alloc/src/lib.rs +++ b/bark-alloc/src/lib.rs @@ -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_::*; diff --git a/bark-alloc/src/pbuf_impl.rs b/bark-alloc/src/pbuf_impl.rs new file mode 100644 index 0000000..39c5ac8 --- /dev/null +++ b/bark-alloc/src/pbuf_impl.rs @@ -0,0 +1,101 @@ +use core::ops::{Deref, DerefMut}; +use core::ptr::NonNull; + +use crate::AllocError; + +#[repr(transparent)] +pub struct FixedBuffer { + pbuf: NonNull, +} + +unsafe impl Send for FixedBuffer {} +unsafe impl Sync for FixedBuffer {} + +impl FixedBuffer { + pub fn alloc_zeroed() -> Result { + 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 Deref for FixedBuffer { + 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 DerefMut for FixedBuffer { + 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 Drop for FixedBuffer { + 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; + } +} diff --git a/bark-protocol/src/packet.rs b/bark-protocol/src/packet.rs index 13a5551..d60feab 100644 --- a/bark-protocol/src/packet.rs +++ b/bark-protocol/src/packet.rs @@ -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::() + size_of::() + @@ -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 { + 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 { + 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 { @@ -140,13 +142,13 @@ impl Audio { size_of::() + size_of::(); - pub fn write() -> AudioWriter { - let packet = Packet::allocate(Magic::AUDIO, Self::LENGTH); + pub fn write() -> Result { + let packet = Packet::allocate(Magic::AUDIO, Self::LENGTH)?; - AudioWriter { + Ok(AudioWriter { packet: Audio(packet), written: SampleDuration::zero(), - } + }) } pub fn parse(packet: Packet) -> Option { @@ -253,8 +255,8 @@ impl Time { const DATA_RANGE: Range = 0..size_of::(); - pub fn allocate() -> Self { - Time(Packet::allocate(Magic::TIME, Self::LENGTH)) + pub fn allocate() -> Result { + Ok(Time(Packet::allocate(Magic::TIME, Self::LENGTH)?)) } pub fn parse(packet: Packet) -> Option { @@ -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 { + Ok(StatsRequest(Packet::allocate(Magic::STATS_REQ, 0)?)) } pub fn parse(packet: Packet) -> Option { @@ -315,17 +317,17 @@ pub struct StatsReply(Packet); impl StatsReply { const LENGTH: usize = size_of::(); - 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 { + 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 { 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::new( StatsReplyFlags::IS_RECEIVER, types::StatsReplyPacket { sid, receiver, node }, diff --git a/bark/src/receive.rs b/bark/src/receive.rs index 78234ec..86c9ddf 100644 --- a/bark/src/receive.rs +++ b/bark/src/receive.rs @@ -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(_)) => { diff --git a/bark/src/socket.rs b/bark/src/socket.rs index a0574e2..653bd85 100644 --- a/bark/src/socket.rs +++ b/bark/src/socket.rs @@ -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); diff --git a/bark/src/stats/mod.rs b/bark/src/stats/mod.rs index d0fb24b..1ce5866 100644 --- a/bark/src/stats/mod.rs +++ b/bark/src/stats/mod.rs @@ -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)); diff --git a/bark/src/stream.rs b/bark/src/stream.rs index f902d7c..a602edb 100644 --- a/bark/src/stream.rs +++ b/bark/src/stream.rs @@ -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(_)) => {