1use core::alloc::Layout;
14use core::ptr::NonNull;
15use core::time::Duration;
16use core::{fmt::Debug, marker::PhantomData};
17use iceoryx2_bb_concurrency::atomic::Ordering;
18
19use alloc::format;
20use alloc::string::ToString;
21use alloc::vec;
22use alloc::vec::Vec;
23
24use iceoryx2_bb_concurrency::atomic::{AtomicU64, AtomicUsize};
25use iceoryx2_bb_concurrency::cell::UnsafeCell;
26use iceoryx2_bb_container::semantic_string::SemanticString;
27use iceoryx2_bb_container::slotmap::{SlotMap, SlotMapKey};
28use iceoryx2_bb_container::string::String;
29use iceoryx2_bb_elementary_traits::allocator::AllocationError;
30use iceoryx2_bb_elementary_traits::non_null::NonNullCompat;
31use iceoryx2_bb_elementary_traits::testing::abandonable::Abandonable;
32use iceoryx2_bb_posix::file::AccessMode;
33use iceoryx2_bb_system_types::file_name::FileName;
34use iceoryx2_bb_system_types::path::Path;
35use iceoryx2_log::fatal_panic;
36use iceoryx2_log::{fail, warn};
37
38use crate::shared_memory::{
39 AllocationStrategy, SegmentId, SharedMemoryForPoolAllocator, ShmPointer,
40};
41use crate::shared_memory::{
42 PointerOffset, SharedMemory, SharedMemoryBuilder, SharedMemoryCreateError,
43 SharedMemoryOpenError, ShmAllocator,
44};
45use crate::shm_allocator::ShmAllocationError;
46use crate::shm_allocator::pool_allocator::PoolAllocator;
47
48use super::{
49 NamedConcept, NamedConceptBuilder, NamedConceptDoesExistError, NamedConceptListError,
50 NamedConceptMgmt, NamedConceptRemoveError, ResizableSharedMemory, ResizableSharedMemoryBuilder,
51 ResizableSharedMemoryForPoolAllocator, ResizableSharedMemoryView,
52 ResizableSharedMemoryViewBuilder, ResizableShmAllocationError,
53};
54
55const MAX_NUMBER_OF_REALLOCATIONS: usize = SegmentId::max_segment_id() as usize + 1;
56const SEGMENT_ID_SEPARATOR: &[u8] = b"__";
57const MANAGEMENT_SUFFIX: &[u8] = b"mgmt";
58const INVALID_KEY: usize = usize::MAX;
59
60#[repr(C)]
61#[derive(Debug)]
62struct SharedState {
63 allocation_strategy: AllocationStrategy,
64 max_number_of_chunks_hint: AtomicU64,
65 max_chunk_size_hint: AtomicU64,
66 max_chunk_alignment_hint: AtomicU64,
67}
68
69#[derive(Debug)]
70struct MemoryConfig<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
71 base_name: FileName,
72 shm: Shm::Configuration,
73 allocator_config_hint: Allocator::Configuration,
74}
75
76#[derive(Debug)]
77struct ViewConfig<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
78 base_name: FileName,
79 shm: Shm::Configuration,
80 shm_builder_timeout: Duration,
81 _data: PhantomData<Allocator>,
82}
83
84#[derive(Debug)]
85struct InternalState<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
86 builder_config: MemoryConfig<Allocator, Shm>,
87 shared_state: SharedState,
88 shared_memory_map: SlotMap<ShmEntry<Allocator, Shm>>,
89 current_idx: SlotMapKey,
90}
91
92impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> Abandonable
93 for InternalState<Allocator, Shm>
94{
95 unsafe fn abandon_in_place(mut this: NonNull<Self>) {
96 let this = unsafe { this.as_mut() };
97 unsafe { SlotMap::abandon_in_place(NonNull::iox2_from_mut(&mut this.shared_memory_map)) };
98 }
99}
100
101#[derive(Debug)]
102struct ShmEntry<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
103 shm: Shm,
104 chunk_count: AtomicU64,
105 _data: PhantomData<Allocator>,
106}
107
108impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> Abandonable
109 for ShmEntry<Allocator, Shm>
110{
111 unsafe fn abandon_in_place(mut this: NonNull<Self>) {
112 let this = unsafe { this.as_mut() };
113 unsafe { Shm::abandon_in_place(NonNull::iox2_from_mut(&mut this.shm)) };
114 }
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118enum ShmEntryState {
119 Empty,
120 NonEmpty,
121}
122
123impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> ShmEntry<Allocator, Shm> {
124 fn new(shm: Shm) -> Self {
125 Self {
126 shm,
127 chunk_count: AtomicU64::new(0),
128 _data: PhantomData,
129 }
130 }
131
132 fn register_offset(&self) {
133 self.chunk_count.fetch_add(1, Ordering::Relaxed);
134 }
135
136 fn unregister_offset(&self) -> ShmEntryState {
137 match self.chunk_count.fetch_sub(1, Ordering::Relaxed) {
138 1 => ShmEntryState::Empty,
139 _ => ShmEntryState::NonEmpty,
140 }
141 }
142}
143
144#[derive(Debug)]
145pub struct DynamicViewBuilder<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
146 config: ViewConfig<Allocator, Shm>,
147}
148
149impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
150 NamedConceptBuilder<DynamicMemory<Allocator, Shm>> for DynamicViewBuilder<Allocator, Shm>
151where
152 Shm::Builder: Debug,
153{
154 fn new(name: &FileName) -> Self {
155 Self {
156 config: ViewConfig {
157 base_name: *name,
158 shm: Shm::Configuration::default(),
159 shm_builder_timeout: Duration::ZERO,
160 _data: PhantomData,
161 },
162 }
163 }
164
165 fn config(mut self, config: &Shm::Configuration) -> Self {
166 self.config.shm = config.clone();
167 self
168 }
169}
170
171impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
172 ResizableSharedMemoryViewBuilder<
173 Allocator,
174 Shm,
175 DynamicMemory<Allocator, Shm>,
176 DynamicView<Allocator, Shm>,
177 > for DynamicViewBuilder<Allocator, Shm>
178where
179 Shm::Builder: Debug,
180{
181 fn timeout(mut self, value: Duration) -> Self {
182 self.config.shm_builder_timeout = value;
183 self
184 }
185
186 fn open(
187 self,
188 access_mode: AccessMode,
189 ) -> Result<DynamicView<Allocator, Shm>, SharedMemoryOpenError> {
190 let origin = format!("{self:?}");
191 let msg = "Unable to open ResizableSharedMemoryView";
192
193 let adjusted_name =
194 DynamicMemory::<Allocator, Shm>::managment_segment_name(&self.config.base_name);
195 let mgmt_segment = fail!(from origin, when Shm::Builder::new(&adjusted_name)
196 .config(&self.config.shm)
197 .has_ownership(false)
198 .open(access_mode),
199 "{msg} since the managment segment could not be opened.");
200
201 let shared_memory_map = SlotMap::new(MAX_NUMBER_OF_REALLOCATIONS);
202
203 Ok(DynamicView {
204 view_config: self.config,
205 mgmt_segment,
206 shared_memory_map: UnsafeCell::new(shared_memory_map),
207 current_idx: AtomicUsize::new(INVALID_KEY),
208 access_mode,
209 _data: PhantomData,
210 })
211 }
212}
213
214#[derive(Debug)]
215pub struct DynamicMemoryBuilder<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
216where
217 Allocator: Debug,
218{
219 config: MemoryConfig<Allocator, Shm>,
220 shared_state: SharedState,
221}
222
223impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
224 NamedConceptBuilder<DynamicMemory<Allocator, Shm>> for DynamicMemoryBuilder<Allocator, Shm>
225where
226 Shm::Builder: Debug,
227{
228 fn new(name: &FileName) -> Self {
229 Self {
230 config: MemoryConfig {
231 base_name: *name,
232 allocator_config_hint: Allocator::Configuration::default(),
233 shm: Shm::Configuration::default(),
234 },
235 shared_state: SharedState {
236 allocation_strategy: AllocationStrategy::default(),
237 max_number_of_chunks_hint: AtomicU64::new(1),
238 max_chunk_size_hint: AtomicU64::new(1),
239 max_chunk_alignment_hint: AtomicU64::new(1),
240 },
241 }
242 }
243
244 fn config(mut self, config: &Shm::Configuration) -> Self {
245 self.config.shm = config.clone();
246 self
247 }
248}
249
250impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
251 ResizableSharedMemoryBuilder<Allocator, Shm, DynamicMemory<Allocator, Shm>>
252 for DynamicMemoryBuilder<Allocator, Shm>
253where
254 Allocator: Debug,
255 Shm::Builder: Debug,
256{
257 fn max_chunk_layout_hint(self, value: Layout) -> Self {
258 self.shared_state
259 .max_chunk_size_hint
260 .store(value.size() as u64, Ordering::Relaxed);
261 self.shared_state
262 .max_chunk_alignment_hint
263 .store(value.align() as u64, Ordering::Relaxed);
264 self
265 }
266
267 fn max_number_of_chunks_hint(self, value: usize) -> Self {
268 self.shared_state
269 .max_number_of_chunks_hint
270 .store(value as u64, Ordering::Relaxed);
271 self
272 }
273
274 fn allocation_strategy(mut self, value: AllocationStrategy) -> Self {
275 self.shared_state.allocation_strategy = value;
276 self
277 }
278
279 fn create(mut self) -> Result<DynamicMemory<Allocator, Shm>, SharedMemoryCreateError> {
280 let msg = "Unable to create ResizableSharedMemory";
281 let origin = format!("{self:?}");
282
283 let hint = Allocator::initial_setup_hint(Layout::new::<u8>(), 1);
284 let adjusted_name =
285 DynamicMemory::<Allocator, Shm>::managment_segment_name(&self.config.base_name);
286 let mgmt_segment = fail!(from origin, when Shm::Builder::new(&adjusted_name)
287 .size(hint.payload_size)
288 .config(&self.config.shm)
289 .has_ownership(true)
290 .create(&hint.config),
291 "{msg} since the management segment could not be created.");
292
293 let hint = Allocator::initial_setup_hint(
294 unsafe {
295 Layout::from_size_align_unchecked(
296 self.shared_state
297 .max_chunk_size_hint
298 .load(Ordering::Relaxed) as usize,
299 self.shared_state
300 .max_chunk_alignment_hint
301 .load(Ordering::Relaxed) as usize,
302 )
303 },
304 self.shared_state
305 .max_number_of_chunks_hint
306 .load(Ordering::Relaxed) as usize,
307 );
308 self.config.allocator_config_hint = hint.config;
309
310 let shm = fail!(from origin, when DynamicMemory::create_segment(&self.config, SegmentId::new(0), hint.payload_size),
311 "Unable to create ResizableSharedMemory since the underlying shared memory could not be created.");
312 let mut shared_memory_map = SlotMap::new(MAX_NUMBER_OF_REALLOCATIONS);
313 let current_idx = fatal_panic!(from origin, when shared_memory_map.insert(ShmEntry::new(shm)).ok_or(""),
314 "This should never happen! {msg} since the newly constructed SlotMap does not have space for one insert.");
315
316 Ok(DynamicMemory {
317 state: UnsafeCell::new(InternalState {
318 builder_config: self.config,
319 shared_memory_map,
320 current_idx,
321 shared_state: self.shared_state,
322 }),
323 mgmt_segment,
324 _data: PhantomData,
325 })
326 }
327}
328
329#[derive(Debug)]
330pub struct DynamicView<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
331 view_config: ViewConfig<Allocator, Shm>,
332 mgmt_segment: Shm,
333 shared_memory_map: UnsafeCell<SlotMap<ShmEntry<Allocator, Shm>>>,
334 current_idx: AtomicUsize,
335 access_mode: AccessMode,
336 _data: PhantomData<Allocator>,
337}
338impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> Abandonable
339 for DynamicView<Allocator, Shm>
340{
341 unsafe fn abandon_in_place(mut this: NonNull<Self>) {
342 let this = unsafe { this.as_mut() };
343 unsafe { Shm::abandon_in_place(NonNull::iox2_from_mut(&mut this.mgmt_segment)) };
344 unsafe {
345 SlotMap::abandon_in_place(NonNull::iox2_from_mut(this.shared_memory_map.get_mut()))
346 };
347 }
348}
349
350impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> DynamicView<Allocator, Shm>
351where
352 Shm::Builder: Debug,
353{
354 fn release_old_unused_segments(
355 shared_memory_map: &mut SlotMap<ShmEntry<Allocator, Shm>>,
356 old_idx: usize,
357 ) {
358 if old_idx == INVALID_KEY {
359 return;
360 }
361
362 let old_key = SlotMapKey::new(old_idx);
363 if let Some(shm) = shared_memory_map.get(old_key) {
364 if shm.chunk_count.load(Ordering::Relaxed) == 0 {
365 shared_memory_map.remove(old_key);
366 }
367 }
368 }
369}
370
371impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
372 ResizableSharedMemoryView<Allocator, Shm> for DynamicView<Allocator, Shm>
373where
374 Shm::Builder: Debug,
375{
376 unsafe fn register_and_translate_offset(
377 &self,
378 offset: PointerOffset,
379 ) -> Result<*const u8, SharedMemoryOpenError> {
380 let msg = "Unable to translate";
381 let segment_id = offset.segment_id();
382 let offset = offset.offset();
383 let key = SlotMapKey::new(segment_id.value() as usize);
384 let shared_memory_map = unsafe { &mut *self.shared_memory_map.get() };
385
386 let payload_start_address = match shared_memory_map.get(key) {
387 None => {
388 let shm = fail!(from self,
389 when DynamicMemory::open_segment(&self.view_config, segment_id, self.access_mode),
390 "{msg} {:?} since the corresponding shared memory segment could not be opened.", offset);
391 let payload_start_address = shm.payload_start_address();
392 let entry = ShmEntry::new(shm);
393 entry.register_offset();
394 shared_memory_map.insert_at(key, entry);
395 Self::release_old_unused_segments(
396 shared_memory_map,
397 self.current_idx.swap(key.value(), Ordering::Relaxed),
398 );
399
400 payload_start_address
401 }
402 Some(entry) => {
403 entry.register_offset();
404 entry.shm.payload_start_address()
405 }
406 };
407
408 Ok((offset + payload_start_address) as *const u8)
409 }
410
411 unsafe fn unregister_offset(&self, offset: PointerOffset) {
412 let segment_id = offset.segment_id();
413 let key = SlotMapKey::new(segment_id.value() as usize);
414 let shared_memory_map = unsafe { &mut *self.shared_memory_map.get() };
415
416 match shared_memory_map.get(key) {
417 Some(entry) => {
418 let state = entry.unregister_offset();
419 if state == ShmEntryState::Empty
420 && self.current_idx.load(Ordering::Relaxed) != key.value()
421 {
422 shared_memory_map.remove(key);
423 }
424 }
425 None => {
426 warn!(from self,
427 "Unable to unregister offset {:?} since the segment id is not mapped.", offset);
428 }
429 }
430 }
431
432 fn number_of_active_segments(&self) -> usize {
433 let shared_memory_map = unsafe { &mut *self.shared_memory_map.get() };
434 shared_memory_map.len()
435 }
436}
437
438#[derive(Debug)]
439pub struct DynamicMemory<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
440 state: UnsafeCell<InternalState<Allocator, Shm>>,
441 mgmt_segment: Shm,
442 _data: PhantomData<Allocator>,
443}
444
445impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> Abandonable
446 for DynamicMemory<Allocator, Shm>
447{
448 unsafe fn abandon_in_place(mut this: NonNull<Self>) {
449 let this = unsafe { this.as_mut() };
450 unsafe { Shm::abandon_in_place(NonNull::iox2_from_mut(&mut this.mgmt_segment)) };
451 }
452}
453
454impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> NamedConcept
455 for DynamicMemory<Allocator, Shm>
456{
457 fn name(&self) -> &FileName {
458 unsafe { &(*self.state.get()).builder_config.base_name }
459 }
460}
461
462impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> NamedConceptMgmt
463 for DynamicMemory<Allocator, Shm>
464where
465 Shm::Builder: Debug,
466{
467 type Configuration = Shm::Configuration;
468
469 unsafe fn remove_cfg(
470 name: &FileName,
471 config: &Shm::Configuration,
472 ) -> Result<bool, NamedConceptRemoveError> {
473 let origin = "resizable_shared_memory::Dynamic::remove_cfg()";
474 let msg = format!("Unable to remove ResizableSharedMemory {name:?}");
475
476 let mgmt_name = Self::managment_segment_name(name);
477 let mut shm_removed = fail!(from origin, when unsafe {Shm::remove_cfg(&mgmt_name, config)},
478 "{msg} since the underlying managment segment could not be removed.");
479
480 let raw_names = match Shm::list_cfg(config) {
481 Ok(names) => names,
482 Err(NamedConceptListError::InsufficientPermissions) => {
483 fail!(from origin, with NamedConceptRemoveError::InsufficientPermissions,
484 "{msg} due to insufficient permissions while listing the underlying SharedMemories.");
485 }
486 Err(e) => {
487 fail!(from origin, with NamedConceptRemoveError::InsufficientPermissions,
488 "{msg} due to an internal error ({:?}) while listing the underlying SharedMemories.", e);
489 }
490 };
491
492 for raw_name in &raw_names {
493 if let Some((extracted_name, _)) = Self::extract_name_and_segment_id(raw_name) {
494 if *name == extracted_name {
495 fail!(from origin, when unsafe { Shm::remove_cfg(raw_name, config)},
496 "{msg} since the underlying SharedMemory could not be removed.");
497 shm_removed = true;
498 }
499 }
500 }
501
502 Ok(shm_removed)
503 }
504
505 fn does_exist_cfg(
506 name: &FileName,
507 config: &Shm::Configuration,
508 ) -> Result<bool, NamedConceptDoesExistError> {
509 let origin = "resizable_shared_memory::Dynamic::does_exist_cfg()";
510 let msg = format!("Unable to determine if ResizableSharedMemory {name:?} exists");
511
512 let mgmt_name = Self::managment_segment_name(name);
513 Ok(
514 fail!(from origin, when Shm::does_exist_cfg(&mgmt_name, config),
515 "{msg} since the existance of the underlying managment segment could not be verified."),
516 )
517 }
518
519 fn list_cfg(config: &Shm::Configuration) -> Result<Vec<FileName>, NamedConceptListError> {
520 let origin = "resizable_shared_memory::Dynamic::list_cfg()";
521 let mut names = vec![];
522 let raw_names = fail!(from origin, when Shm::list_cfg(config),
523 "Unable to list ResizableSharedMemories since the underlying SharedMemories could not be listed.");
524
525 for raw_name in &raw_names {
526 if let Some(name) = Self::extract_name_from_management_segment(raw_name) {
527 names.push(name);
528 }
529 }
530
531 Ok(names)
532 }
533
534 fn remove_path_hint(value: &Path) -> Result<(), super::NamedConceptPathHintRemoveError> {
535 Shm::remove_path_hint(value)
536 }
537}
538
539impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> DynamicMemory<Allocator, Shm>
540where
541 Shm::Builder: Debug,
542{
543 fn managment_segment_name(base_name: &FileName) -> FileName {
544 let origin = "resizable_shared_memory::DynamicMemory::managment_segment_name()";
545 let msg = "Unable to construct management segment name";
546 let mut adjusted_name = *base_name;
547 fatal_panic!(from origin, when adjusted_name.push_bytes(SEGMENT_ID_SEPARATOR),
548 "This should never happen! {msg} since it would result in an invalid file name.");
549 fatal_panic!(from origin, when adjusted_name.push_bytes(MANAGEMENT_SUFFIX),
550 "This should never happen! {msg} since it would result in an invalid file name.");
551 adjusted_name
552 }
553
554 fn extract_name_from_management_segment(name: &FileName) -> Option<FileName> {
555 let mut name = *name;
556 if let Ok(true) = name.strip_suffix(MANAGEMENT_SUFFIX) {
557 if let Ok(true) = name.strip_suffix(SEGMENT_ID_SEPARATOR) {
558 return Some(name);
559 }
560 }
561
562 None
563 }
564
565 fn extract_name_and_segment_id(name: &FileName) -> Option<(FileName, SegmentId)> {
566 let origin = "resizable_shared_memory::DynamicMemory::extract_name_and_segment_id()";
567 let msg = "Unable to extract name and segment id";
568 if let Some(pos) = name.rfind(SEGMENT_ID_SEPARATOR) {
569 let segment_id_start_pos = pos + SEGMENT_ID_SEPARATOR.len();
570 if name.len() < segment_id_start_pos {
571 return None;
572 }
573
574 let number_of_segment_id_digits =
575 SegmentId::max_segment_id().checked_ilog10().unwrap_or(0) + 1;
576
577 if name.len() > segment_id_start_pos + number_of_segment_id_digits as usize {
578 return None;
579 }
580
581 let mut raw_segment_id = *name.as_string();
582 raw_segment_id.remove_range(0, segment_id_start_pos);
583
584 for byte in raw_segment_id.as_bytes() {
586 if !byte.is_ascii_digit() {
587 return None;
588 }
589 }
590
591 let segment_id_value = fatal_panic!(from origin,
592 when alloc::string::String::from_utf8_lossy(raw_segment_id.as_bytes()).parse::<u64>(),
593 "This should never happen! {msg} since the segment_id raw value is not an unsigned integer.");
594
595 if segment_id_value > SegmentId::max_segment_id() as u64 {
596 return None;
597 }
598
599 let mut name = *name;
600 fatal_panic!(from origin,
601 when name.remove_range(pos, name.len() - pos),
602 "This should never happen! {msg} since the shared memory segment is an invalid file name without the segment id suffix.");
603
604 return Some((name, SegmentId::new(segment_id_value as u8)));
605 }
606
607 None
608 }
609
610 #[allow(clippy::mut_from_ref)] fn state_mut(&self) -> &mut InternalState<Allocator, Shm> {
612 unsafe { &mut *self.state.get() }
613 }
614
615 fn state(&self) -> &InternalState<Allocator, Shm> {
616 unsafe { &*self.state.get() }
617 }
618
619 fn create_segment(
620 config: &MemoryConfig<Allocator, Shm>,
621 segment_id: SegmentId,
622 payload_size: usize,
623 ) -> Result<Shm, SharedMemoryCreateError> {
624 Self::segment_builder(&config.base_name, &config.shm, segment_id)
625 .has_ownership(true)
626 .size(payload_size)
627 .create(&config.allocator_config_hint)
628 }
629
630 fn open_segment(
631 config: &ViewConfig<Allocator, Shm>,
632 segment_id: SegmentId,
633 access_mode: AccessMode,
634 ) -> Result<Shm, SharedMemoryOpenError> {
635 Self::segment_builder(&config.base_name, &config.shm, segment_id)
636 .has_ownership(false)
637 .timeout(config.shm_builder_timeout)
638 .open(access_mode)
639 }
640
641 fn segment_builder(
642 base_name: &FileName,
643 config: &Shm::Configuration,
644 segment_id: SegmentId,
645 ) -> Shm::Builder {
646 let msg = "This should never happen! Unable to create additional shared memory segment since it would result in an invalid shared memory name.";
647 let mut adjusted_name = *base_name;
648 fatal_panic!(from config, when adjusted_name.push_bytes(SEGMENT_ID_SEPARATOR), "{msg}");
649 fatal_panic!(from config, when adjusted_name.push_bytes(segment_id.value().to_string().as_bytes()), "{msg}");
650 Shm::Builder::new(&adjusted_name).config(config)
651 }
652
653 fn create_resized_segment(
654 &self,
655 shm: &Shm,
656 layout: Layout,
657 ) -> Result<(), ResizableShmAllocationError> {
658 let msg = "Unable to create resized segment for";
659 let state = self.state_mut();
660 let adjusted_segment_setup = shm
661 .allocator()
662 .resize_hint(layout, state.shared_state.allocation_strategy);
663 let new_number_of_reallocations = state.current_idx.value() + 1;
664 let segment_id = if new_number_of_reallocations < MAX_NUMBER_OF_REALLOCATIONS {
665 SlotMapKey::new(new_number_of_reallocations)
666 } else {
667 fail!(from self, with ResizableShmAllocationError::MaxReallocationsReached,
668 "{msg} {:?} since it would exceed the maximum amount of reallocations of {}. With a better configuration hint, this issue can be avoided.",
669 layout, Self::max_number_of_reallocations());
670 };
671
672 state.builder_config.allocator_config_hint = adjusted_segment_setup.config;
673 let shm = Self::create_segment(
674 &state.builder_config,
675 SegmentId::new(segment_id.value() as u8),
676 adjusted_segment_setup.payload_size,
677 )?;
678
679 match state.shared_memory_map.get(state.current_idx) {
680 Some(segment) => {
681 if segment.chunk_count.load(Ordering::Relaxed) == 0 {
682 state.shared_memory_map.remove(state.current_idx);
683 }
684 }
685 None => {
686 fatal_panic!(from self,
687 "This should never happen! {msg} {:?} since the current segment id is unavailable.",
688 layout)
689 }
690 }
691
692 state
693 .shared_memory_map
694 .insert_at(segment_id, ShmEntry::new(shm));
695 state.current_idx = segment_id;
696
697 Ok(())
698 }
699
700 fn handle_reallocation(
701 &self,
702 e: ShmAllocationError,
703 state: &InternalState<Allocator, Shm>,
704 layout: Layout,
705 shm: &Shm,
706 ) -> Result<(), ResizableShmAllocationError> {
707 let msg = "Unable to allocate memory";
708 if e == ShmAllocationError::AllocationError(AllocationError::OutOfMemory)
709 || e == ShmAllocationError::ExceedsMaxSupportedAlignment
710 || e == ShmAllocationError::AllocationError(AllocationError::SizeTooLarge)
711 {
712 if state.shared_state.allocation_strategy == AllocationStrategy::Static {
713 fail!(from self, with e.into(),
714 "{msg} since there is not enough memory left ({:?}) and the allocation strategy {:?} forbids reallocation.",
715 e, state.shared_state.allocation_strategy);
716 } else {
717 self.create_resized_segment(shm, layout)?;
718 Ok(())
719 }
720 } else {
721 fail!(from self, with e.into(), "{msg} due to {:?}.", e);
722 }
723 }
724
725 unsafe fn perform_deallocation<F: FnMut(&ShmEntry<Allocator, Shm>)>(
726 &self,
727 offset: PointerOffset,
728 mut deallocation_call: F,
729 ) {
730 let segment_id = SlotMapKey::new(offset.segment_id().value() as usize);
731 let state = self.state_mut();
732 match state.shared_memory_map.get(segment_id) {
733 Some(entry) => {
734 deallocation_call(entry);
735 if entry.unregister_offset() == ShmEntryState::Empty
736 && segment_id != state.current_idx
737 {
738 state.shared_memory_map.remove(segment_id);
739 }
740 }
741 None => fatal_panic!(from self,
742 "This should never happen! Unable to deallocate {:?} since the corresponding shared memory segment is not available!", offset),
743 }
744 }
745}
746
747impl<Shm: SharedMemoryForPoolAllocator> ResizableSharedMemoryForPoolAllocator<Shm>
748 for DynamicMemory<PoolAllocator, Shm>
749where
750 Shm::Builder: Debug,
751{
752 unsafe fn deallocate_bucket(&self, offset: PointerOffset) {
753 unsafe {
754 self.perform_deallocation(offset, |entry| entry.shm.deallocate_bucket(offset));
755 }
756 }
757
758 fn bucket_size(&self, segment_id: SegmentId) -> usize {
759 let segment_id_key = SlotMapKey::new(segment_id.value() as usize);
760 match self.state_mut().shared_memory_map.get(segment_id_key) {
761 Some(entry) => entry.shm.bucket_size(),
762 None => fatal_panic!(from self,
763 "This should never happen! Unable to acquire bucket size since the segment {:?} does not exist.",
764 segment_id),
765 }
766 }
767}
768
769impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> ResizableSharedMemory<Allocator, Shm>
770 for DynamicMemory<Allocator, Shm>
771where
772 Shm::Builder: Debug,
773{
774 type ViewBuilder = DynamicViewBuilder<Allocator, Shm>;
775 type MemoryBuilder = DynamicMemoryBuilder<Allocator, Shm>;
776 type View = DynamicView<Allocator, Shm>;
777
778 fn max_number_of_reallocations() -> usize {
779 MAX_NUMBER_OF_REALLOCATIONS
780 }
781
782 fn number_of_active_segments(&self) -> usize {
783 self.state().shared_memory_map.len()
784 }
785
786 fn allocate(&self, layout: Layout) -> Result<ShmPointer, ResizableShmAllocationError> {
787 let msg = "Unable to allocate memory";
788 let state = self.state_mut();
789
790 loop {
791 match state.shared_memory_map.get(state.current_idx) {
792 Some(entry) => match entry.shm.allocate(layout) {
793 Ok(mut ptr) => {
794 entry.register_offset();
795 ptr.offset
796 .set_segment_id(SegmentId::new(state.current_idx.value() as u8));
797 return Ok(ptr);
798 }
799 Err(e) => self.handle_reallocation(e, state, layout, &entry.shm)?,
800 },
801 None => fatal_panic!(from self,
802 "This should never happen! {msg} since the current shared memory segment is not available!"),
803 }
804 }
805 }
806
807 unsafe fn deallocate(&self, offset: PointerOffset, layout: Layout) {
808 unsafe {
809 self.perform_deallocation(offset, |entry| entry.shm.deallocate(offset, layout));
810 }
811 }
812}