iceoryx2_cal/shm_allocator/mod.rs
1// Copyright (c) 2023 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
13pub mod bump_allocator;
14pub mod pointer_offset;
15pub mod pool_allocator;
16
17use core::{alloc::Layout, fmt::Debug, ptr::NonNull};
18
19use iceoryx2_bb_elementary::enum_gen;
20pub use iceoryx2_bb_elementary_traits::allocator::AllocationError;
21use iceoryx2_bb_elementary_traits::allocator::BaseAllocator;
22pub use pointer_offset::*;
23use serde::{Deserialize, Serialize};
24
25/// Trait that identifies a configuration of a [`ShmAllocator`].
26pub trait ShmAllocatorConfig: Copy + Default + Debug + Send {}
27
28enum_gen! {
29/// Describes the errors that can occur when [`ShmAllocator::allocate()`] is called.
30 ShmAllocationError
31 entry:
32 ExceedsMaxSupportedAlignment
33 mapping:
34 AllocationError
35}
36
37/// Describes generically an [`AllocationStrategy`], meaning how the memory is increased when the
38/// available memory is insufficient.
39#[derive(Clone, Copy, Eq, PartialEq, Debug, Default, Serialize, Deserialize)]
40pub enum AllocationStrategy {
41 /// Increases the memory so that it perfectly fits the new size requirements. This may lead
42 /// to a lot of reallocations but has the benefit that no byte is wasted.
43 BestFit,
44 /// Increases the memory by rounding the increased memory size up to the next power of two.
45 /// Reduces reallocations a lot at the cost of increased memory usage.
46 PowerOfTwo,
47 /// The memory is not increased. This may lead to an out-of-memory error when allocating.
48 #[default]
49 Static,
50}
51
52/// Describes error that may occur when a [`ShmAllocator`] is initialized.
53#[derive(Clone, Copy, Eq, PartialEq, Debug)]
54pub enum ShmAllocatorInitError {
55 /// The [`SharedMemory`](crate::shared_memory::SharedMemory) max supported alignment does not
56 /// satisfy the required alignment of the [`ShmAllocator`].
57 MaxSupportedMemoryAlignmentInsufficient,
58 /// The [`ShmAllocator`] requires more memory to initialize than available.
59 AllocationFailed,
60}
61
62impl core::fmt::Display for ShmAllocatorInitError {
63 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
64 write!(f, "ShmAllocatorInitError::{self:?}")
65 }
66}
67
68impl core::error::Error for ShmAllocatorInitError {}
69
70/// Returned by [`ShmAllocator::resize_hint()`] and [`ShmAllocator::initial_setup_hint()`].
71/// It contains a payload size and [`ShmAllocator`] configuration suggestion for the given
72/// parameters.
73pub struct SharedMemorySetupHint<Config: ShmAllocatorConfig> {
74 /// The payload size of the [`SharedMemory`](crate::shared_memory::SharedMemory)
75 pub payload_size: usize,
76 /// The [`ShmAllocatorConfig`] that shall be used for the
77 /// [`SharedMemory`](crate::shared_memory::SharedMemory)
78 pub config: Config,
79}
80
81/// Every allocator implementation must be relocatable. The allocator itself must be stored either
82/// in the same shared memory segment or in a separate shared memory segment of a different type
83/// but accessible by all participating processes.
84pub trait ShmAllocator: Debug + Send + Sync + 'static {
85 type Configuration: ShmAllocatorConfig;
86 /// Suggest a new payload size by considering the current allocation state in combination with
87 /// a provided [`AllocationStrategy`] and a `layout` that shall be allocatable.
88 fn resize_hint(
89 &self,
90 layout: Layout,
91 strategy: AllocationStrategy,
92 ) -> SharedMemorySetupHint<Self::Configuration>;
93
94 /// Suggest a managed payload size under a provided configuration assuming that at most
95 /// `max_number_of_chunks` of memory are in use in parallel.
96 fn initial_setup_hint(
97 max_chunk_layout: Layout,
98 max_number_of_chunks: usize,
99 ) -> SharedMemorySetupHint<Self::Configuration>;
100
101 /// Returns the required memory size of the additional dynamic part of the allocator that is
102 /// allocated in [`ShmAllocator::init()`].
103 fn management_size(memory_size: usize, config: &Self::Configuration) -> usize;
104
105 /// Creates a new uninitialized shared memory allocator.
106 ///
107 /// # Safety
108 ///
109 /// * the method [`ShmAllocator::init()`] must be called before any other method is called
110 ///
111 unsafe fn new_uninit(
112 max_supported_alignment_by_memory: usize,
113 managed_memory: NonNull<[u8]>,
114 config: &Self::Configuration,
115 ) -> Self;
116
117 /// Initializes the shared memory allocator.
118 ///
119 /// # Safety
120 ///
121 /// * must be called only once
122 /// * must be called before any other method is called
123 ///
124 unsafe fn init<Allocator: BaseAllocator>(
125 &mut self,
126 mgmt_allocator: &Allocator,
127 ) -> Result<(), ShmAllocatorInitError>;
128
129 /// Returns the unique id of the allocator. It is inequal to any other
130 /// [`ShmAllocator::unique_id()`]
131 fn unique_id() -> u8;
132
133 /// Returns the max supported alignment by the allocator.
134 fn max_alignment(&self) -> usize;
135
136 /// Returns the offset to the beginning of the allocator payload. The smallest offset a user
137 /// can allocate.
138 fn relative_start_address(&self) -> usize;
139
140 /// Allocates memory and returns the pointer offset.
141 ///
142 /// # Safety
143 ///
144 /// * [`ShmAllocator::init()`] must have been called before using this method
145 ///
146 unsafe fn allocate(&self, layout: Layout) -> Result<PointerOffset, ShmAllocationError>;
147
148 /// Deallocates a previously allocated pointer offset
149 ///
150 /// # Safety
151 ///
152 /// * the provided distance must have been allocated before with the same layout
153 /// * [`ShmAllocator::init()`] must have been called before using this method
154 ///
155 unsafe fn deallocate(&self, distance: PointerOffset, layout: Layout);
156}