Skip to main content

iceoryx2_cal/resizable_shared_memory/
dynamic.rs

1// Copyright (c) 2024 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13use 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            // check nymber of digits
585            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)] // internal convenience function
611    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}