iceoryx2_cal/shm_allocator/
pool_allocator.rs1use core::{alloc::Layout, ptr::NonNull};
14
15use crate::shm_allocator::{ShmAllocator, ShmAllocatorConfig};
16
17use iceoryx2_bb_concurrency::atomic::AtomicUsize;
18use iceoryx2_bb_concurrency::atomic::Ordering;
19use iceoryx2_bb_elementary_traits::allocator::BaseAllocator;
20use iceoryx2_log::fail;
21
22use super::{
23 AllocationStrategy, PointerOffset, SharedMemorySetupHint, ShmAllocationError,
24 ShmAllocatorInitError,
25};
26
27#[derive(Clone, Copy, Debug)]
28pub struct Config {
29 pub bucket_layout: Layout,
30}
31
32impl Default for Config {
33 fn default() -> Self {
34 Self {
35 bucket_layout: unsafe { Layout::from_size_align_unchecked(1024, 8) },
36 }
37 }
38}
39
40impl ShmAllocatorConfig for Config {}
41
42#[derive(Debug)]
43pub struct PoolAllocator {
44 allocator: iceoryx2_bb_memory::pool_allocator::PoolAllocator,
45 base_address: usize,
49 max_supported_alignment_by_memory: usize,
50 number_of_used_buckets: AtomicUsize,
51}
52
53impl PoolAllocator {
54 pub fn bucket_size(&self) -> usize {
55 self.allocator.bucket_size()
56 }
57
58 pub fn number_of_buckets(&self) -> u32 {
59 self.allocator.number_of_buckets()
60 }
61
62 pub unsafe fn deallocate_bucket(&self, offset: PointerOffset) {
66 self.number_of_used_buckets.fetch_sub(1, Ordering::Relaxed);
67 unsafe {
68 self.allocator.deallocate_bucket(NonNull::new_unchecked(
69 (offset.offset() + self.allocator.start_address()) as *mut u8,
70 ));
71 }
72 }
73}
74
75impl ShmAllocator for PoolAllocator {
76 type Configuration = Config;
77
78 fn resize_hint(
79 &self,
80 layout: Layout,
81 strategy: AllocationStrategy,
82 ) -> SharedMemorySetupHint<Self::Configuration> {
83 let current_layout = unsafe {
84 Layout::from_size_align_unchecked(
85 self.allocator.bucket_size(),
86 self.allocator.max_alignment(),
87 )
88 };
89
90 let adjusted_number_of_buckets = if self.number_of_used_buckets.load(Ordering::Relaxed)
91 == self.number_of_buckets() as usize
92 {
93 match strategy {
94 AllocationStrategy::BestFit => self.allocator.number_of_buckets() + 1,
95 AllocationStrategy::PowerOfTwo => {
96 (self.allocator.number_of_buckets() + 1).next_power_of_two()
97 }
98 AllocationStrategy::Static => self.allocator.number_of_buckets(),
99 }
100 } else {
101 self.number_of_buckets()
102 };
103
104 let adjusted_layout =
105 if current_layout.size() < layout.size() || current_layout.align() < layout.align() {
106 match strategy {
107 AllocationStrategy::Static => current_layout,
108 AllocationStrategy::BestFit => unsafe {
109 let align = layout.align().max(current_layout.align());
110 let size = layout
111 .size()
112 .max(current_layout.size())
113 .next_multiple_of(align);
114 Layout::from_size_align_unchecked(size, align)
115 },
116 AllocationStrategy::PowerOfTwo => unsafe {
117 let align = layout
118 .align()
119 .max(current_layout.align())
120 .next_power_of_two();
121 let size = layout
122 .size()
123 .max(current_layout.size())
124 .next_power_of_two()
125 .next_multiple_of(align);
126 Layout::from_size_align_unchecked(size, align)
127 },
128 }
129 } else {
130 current_layout
131 };
132
133 Self::initial_setup_hint(adjusted_layout, adjusted_number_of_buckets as usize)
134 }
135
136 fn initial_setup_hint(
137 max_chunk_layout: Layout,
138 max_number_of_chunks: usize,
139 ) -> SharedMemorySetupHint<Self::Configuration> {
140 SharedMemorySetupHint {
141 payload_size: max_chunk_layout.size() * max_number_of_chunks,
142 config: Self::Configuration {
143 bucket_layout: max_chunk_layout,
144 },
145 }
146 }
147
148 fn management_size(memory_size: usize, config: &Self::Configuration) -> usize {
149 iceoryx2_bb_memory::pool_allocator::PoolAllocator::memory_size(
150 config.bucket_layout,
151 memory_size,
152 )
153 }
154
155 fn relative_start_address(&self) -> usize {
156 self.allocator.start_address() - self.base_address
157 }
158
159 unsafe fn new_uninit(
160 max_supported_alignment_by_memory: usize,
161 managed_memory: NonNull<[u8]>,
162 config: &Self::Configuration,
163 ) -> Self {
164 Self {
165 allocator: unsafe {
166 iceoryx2_bb_memory::pool_allocator::PoolAllocator::new_uninit(
167 config.bucket_layout,
168 NonNull::new_unchecked(managed_memory.as_ptr() as *mut u8),
169 managed_memory.len(),
170 )
171 },
172 base_address: (managed_memory.as_ptr() as *mut u8) as usize,
173 max_supported_alignment_by_memory,
174 number_of_used_buckets: AtomicUsize::new(0),
175 }
176 }
177
178 fn max_alignment(&self) -> usize {
179 self.allocator.max_alignment()
180 }
181
182 unsafe fn init<Allocator: BaseAllocator>(
183 &mut self,
184 mgmt_allocator: &Allocator,
185 ) -> Result<(), ShmAllocatorInitError> {
186 let msg = "Unable to initialize allocator";
187 if self.max_supported_alignment_by_memory < self.max_alignment() {
188 fail!(from self, with ShmAllocatorInitError::MaxSupportedMemoryAlignmentInsufficient,
189 "{} since the required alignment {} exceeds the maximum supported alignment {} of the memory.",
190 msg, self.max_alignment(), self.max_supported_alignment_by_memory);
191 }
192
193 fail!(from self, when unsafe { self.allocator.init(mgmt_allocator) },
194 with ShmAllocatorInitError::AllocationFailed,
195 "{} since the allocation of the allocator managment memory failed.", msg);
196
197 Ok(())
198 }
199
200 fn unique_id() -> u8 {
201 0
202 }
203
204 unsafe fn allocate(&self, layout: Layout) -> Result<PointerOffset, ShmAllocationError> {
205 let msg = "Unable to allocate memory";
206 if layout.align() > self.max_alignment() {
207 fail!(from self, with ShmAllocationError::ExceedsMaxSupportedAlignment,
208 "{} since an alignment of {} exceeds the maximum supported alignment of {}.",
209 msg, layout.align(), self.max_alignment());
210 }
211
212 let chunk = fail!(from self, when self.allocator.allocate(layout), "{}.", msg);
213 self.number_of_used_buckets.fetch_add(1, Ordering::Relaxed);
214 Ok(PointerOffset::new(
215 (chunk.as_ptr() as *const u8) as usize - self.allocator.start_address(),
216 ))
217 }
218
219 unsafe fn deallocate(&self, offset: PointerOffset, _layout: Layout) {
220 unsafe {
221 self.deallocate_bucket(offset);
222 }
223 }
224}