zenoh_shm/api/protocol_implementations/posix/
posix_shm_provider_backend_buddy.rs1use std::{
16 alloc::Layout,
17 ptr::NonNull,
18 sync::{Arc, Mutex},
19};
20
21use buddy_system_allocator::Heap;
22use zenoh_core::{zlock, Resolvable, Wait};
23use zenoh_result::ZResult;
24
25use super::posix_shm_segment::PosixShmSegment;
26use crate::api::{
27 common::{types::ProtocolID, with_id::WithProtocolID},
28 protocol_implementations::posix::protocol_id::POSIX_PROTOCOL_ID,
29 provider::{
30 chunk::ChunkDescriptor,
31 memory_layout::MemoryLayout,
32 shm_provider_backend::ShmProviderBackend,
33 types::{AllocAlignment, ChunkAllocResult, ZAllocError, ZLayoutError},
34 },
35};
36
37#[zenoh_macros::unstable_doc]
39pub struct PosixShmProviderBackendBuddyBuilder<Layout> {
40 layout: Layout,
41}
42
43#[zenoh_macros::unstable_doc]
44impl<Layout> Resolvable for PosixShmProviderBackendBuddyBuilder<Layout> {
45 type To = ZResult<PosixShmProviderBackendBuddy>;
46}
47
48#[zenoh_macros::unstable_doc]
49impl<Layout: TryInto<MemoryLayout>> Wait for PosixShmProviderBackendBuddyBuilder<Layout>
50where
51 Layout::Error: Into<ZLayoutError>,
52{
53 fn wait(self) -> <Self as Resolvable>::To {
54 PosixShmProviderBackendBuddy::new(&self.layout.try_into().map_err(Into::into)?)
55 }
56}
57
58#[zenoh_macros::unstable_doc]
62pub struct PosixShmProviderBackendBuddy {
63 segment: Arc<PosixShmSegment>,
64 heap: Mutex<Heap<BUDDY_ORDER>>,
65 alignment: AllocAlignment,
66}
67
68const BUDDY_ORDER: usize = 30;
70
71impl PosixShmProviderBackendBuddy {
72 #[zenoh_macros::unstable_doc]
74 pub fn builder<Layout>(layout: Layout) -> PosixShmProviderBackendBuddyBuilder<Layout> {
75 PosixShmProviderBackendBuddyBuilder { layout }
76 }
77
78 fn new(layout: &MemoryLayout) -> ZResult<Self> {
79 let segment = Arc::new(PosixShmSegment::create(layout.size())?);
80
81 let real_size = segment.segment.elem_count().get();
84
85 let mut heap = Heap::empty();
86
87 unsafe { heap.init(segment.segment.elem_mut(0) as usize, real_size) };
88
89 tracing::trace!(
90 "Created PosixShmProviderBackendBuddy id {}, layout {:?}",
91 segment.segment.id(),
92 layout
93 );
94
95 Ok(Self {
96 segment,
97 heap: Mutex::new(heap),
98 alignment: layout.alignment(),
99 })
100 }
101}
102
103impl WithProtocolID for PosixShmProviderBackendBuddy {
104 fn id(&self) -> ProtocolID {
105 POSIX_PROTOCOL_ID
106 }
107}
108
109impl ShmProviderBackend for PosixShmProviderBackendBuddy {
110 fn alloc(&self, layout: &MemoryLayout) -> ChunkAllocResult {
111 tracing::trace!("PosixShmProviderBackendBuddy::alloc({:?})", layout);
112
113 let alloc_layout = unsafe {
114 Layout::from_size_align_unchecked(
115 layout.size().get(),
116 layout.alignment().get_alignment_value().get(),
117 )
118 };
119
120 let alloc = {
121 let mut lock = zlock!(self.heap);
122 lock.alloc(alloc_layout)
123 };
124
125 match alloc {
126 Ok(buf) => Ok(self.segment.clone().allocated_chunk(buf, layout)),
127 Err(_) => Err(ZAllocError::OutOfMemory),
128 }
129 }
130
131 fn free(&self, chunk: &ChunkDescriptor) {
132 let alloc_layout = unsafe {
133 Layout::from_size_align_unchecked(
134 chunk.len.get(),
135 self.alignment.get_alignment_value().get(),
136 )
137 };
138
139 let ptr = unsafe { self.segment.segment.elem_mut(chunk.chunk) };
140
141 unsafe { zlock!(self.heap).dealloc(NonNull::new_unchecked(ptr), alloc_layout) };
142 }
143
144 fn defragment(&self) -> usize {
145 0
146 }
147
148 fn available(&self) -> usize {
149 let lock = zlock!(self.heap);
150 lock.stats_total_bytes() - lock.stats_alloc_actual()
151 }
152
153 fn layout_for(&self, layout: MemoryLayout) -> Result<MemoryLayout, ZLayoutError> {
154 layout.extend(self.alignment)
155 }
156}