1use core::alloc::Layout;
14
15use iceoryx2_bb_log::fail;
16use iceoryx2_bb_system_types::file_name::FileName;
17use iceoryx2_cal::{
18 event::NamedConceptBuilder,
19 resizable_shared_memory::*,
20 shared_memory::{
21 SharedMemory, SharedMemoryBuilder, SharedMemoryCreateError, SharedMemoryForPoolAllocator,
22 SharedMemoryOpenError, ShmPointer,
23 },
24 shm_allocator::{
25 self, pool_allocator::PoolAllocator, AllocationError, AllocationStrategy, PointerOffset,
26 SegmentId, ShmAllocationError,
27 },
28};
29
30use crate::{
31 config,
32 service::{
33 self,
34 config_scheme::{data_segment_config, resizable_data_segment_config},
35 },
36};
37
38#[repr(C)]
40#[derive(Debug, Clone, Copy, Eq, PartialEq)]
41pub enum DataSegmentType {
42 Dynamic,
44 Static,
46}
47
48impl DataSegmentType {
49 pub(crate) fn new_from_allocation_strategy(v: AllocationStrategy) -> Self {
50 match v {
51 AllocationStrategy::Static => DataSegmentType::Static,
52 _ => DataSegmentType::Dynamic,
53 }
54 }
55}
56
57#[derive(Debug)]
58enum MemoryType<Service: service::Service> {
59 Static(Service::SharedMemory),
60 Dynamic(Service::ResizableSharedMemory),
61}
62
63#[derive(Debug)]
64pub(crate) struct DataSegment<Service: service::Service> {
65 memory: MemoryType<Service>,
66}
67
68impl<Service: service::Service> DataSegment<Service> {
69 pub(crate) fn create_static_segment(
70 segment_name: &FileName,
71 chunk_layout: Layout,
72 global_config: &config::Config,
73 number_of_chunks: usize,
74 ) -> Result<Self, SharedMemoryCreateError> {
75 let allocator_config = shm_allocator::pool_allocator::Config {
76 bucket_layout: chunk_layout,
77 };
78 let msg = "Unable to create the static data segment since the underlying shared memory could not be created.";
79 let origin = "DataSegment::create_static_segment()";
80
81 let segment_config = data_segment_config::<Service>(global_config);
82 let memory = fail!(from origin,
83 when <<Service::SharedMemory as SharedMemory<PoolAllocator>>::Builder as NamedConceptBuilder<
84 Service::SharedMemory,
85 >>::new(segment_name)
86 .config(&segment_config)
87 .size(chunk_layout.size() * number_of_chunks + chunk_layout.align() - 1)
88 .create(&allocator_config),
89 "{msg}");
90
91 Ok(Self {
92 memory: MemoryType::Static(memory),
93 })
94 }
95
96 pub(crate) fn create_dynamic_segment(
97 segment_name: &FileName,
98 chunk_layout: Layout,
99 global_config: &config::Config,
100 number_of_chunks: usize,
101 allocation_strategy: AllocationStrategy,
102 ) -> Result<Self, SharedMemoryCreateError> {
103 let msg = "Unable to create the dynamic data segment since the underlying shared memory could not be created.";
104 let origin = "DataSegment::create_dynamic_segment()";
105
106 let segment_config = resizable_data_segment_config::<Service>(global_config);
107 let memory = fail!(from origin,
108 when <<Service::ResizableSharedMemory as ResizableSharedMemory<
109 PoolAllocator,
110 Service::SharedMemory,
111 >>::MemoryBuilder as NamedConceptBuilder<Service::ResizableSharedMemory>>::new(
112 segment_name,
113 )
114 .config(&segment_config)
115 .max_number_of_chunks_hint(number_of_chunks)
116 .max_chunk_layout_hint(chunk_layout)
117 .allocation_strategy(allocation_strategy)
118 .create(),
119 "{msg}");
120
121 Ok(Self {
122 memory: MemoryType::Dynamic(memory),
123 })
124 }
125
126 pub(crate) fn allocate(&self, layout: Layout) -> Result<ShmPointer, ShmAllocationError> {
127 let msg = "Unable to allocate memory from the data segment";
128 match &self.memory {
129 MemoryType::Static(memory) => Ok(fail!(from self, when memory.allocate(layout),
130 "{msg}.")),
131 MemoryType::Dynamic(memory) => match memory.allocate(layout) {
132 Ok(ptr) => Ok(ptr),
133 Err(ResizableShmAllocationError::ShmAllocationError(e)) => {
134 fail!(from self, with e,
135 "{msg} caused by {:?}.", e);
136 }
137 Err(ResizableShmAllocationError::MaxReallocationsReached) => {
138 fail!(from self,
139 with ShmAllocationError::AllocationError(AllocationError::OutOfMemory),
140 "{msg} since the maxmimum number of reallocations was reached. Try to provide initial_max_slice_len({}) as hint when creating the publisher to have a more fitting initial setup.", layout.size());
141 }
142 Err(ResizableShmAllocationError::SharedMemoryCreateError(e)) => {
143 fail!(from self,
144 with ShmAllocationError::AllocationError(AllocationError::InternalError),
145 "{msg} since the shared memory segment creation failed while resizing the memory due to ({:?}).", e);
146 }
147 },
148 }
149 }
150
151 pub(crate) unsafe fn deallocate_bucket(&self, offset: PointerOffset) {
152 match &self.memory {
153 MemoryType::Static(memory) => memory.deallocate_bucket(offset),
154 MemoryType::Dynamic(memory) => memory.deallocate_bucket(offset),
155 }
156 }
157
158 pub(crate) fn bucket_size(&self, segment_id: SegmentId) -> usize {
159 match &self.memory {
160 MemoryType::Static(memory) => memory.bucket_size(),
161 MemoryType::Dynamic(memory) => memory.bucket_size(segment_id),
162 }
163 }
164
165 pub(crate) fn max_number_of_segments(data_segment_type: DataSegmentType) -> u8 {
166 match data_segment_type {
167 DataSegmentType::Static => 1,
168 DataSegmentType::Dynamic => {
169 (Service::ResizableSharedMemory::max_number_of_reallocations() - 1) as u8
170 }
171 }
172 }
173}
174
175#[derive(Debug)]
176enum MemoryViewType<Service: service::Service> {
177 Static(Service::SharedMemory),
178 Dynamic(
179 <Service::ResizableSharedMemory as ResizableSharedMemory<
180 PoolAllocator,
181 Service::SharedMemory,
182 >>::View,
183 ),
184}
185
186#[derive(Debug)]
187pub(crate) struct DataSegmentView<Service: service::Service> {
188 memory: MemoryViewType<Service>,
189}
190
191impl<Service: service::Service> DataSegmentView<Service> {
192 pub(crate) fn open_static_segment(
193 segment_name: &FileName,
194 global_config: &config::Config,
195 ) -> Result<Self, SharedMemoryOpenError> {
196 let origin = "DataSegment::open()";
197 let msg =
198 "Unable to open data segment since the underlying shared memory could not be opened.";
199
200 let segment_config = data_segment_config::<Service>(global_config);
201 let memory = fail!(from origin,
202 when <Service::SharedMemory as SharedMemory<PoolAllocator>>::
203 Builder::new(segment_name)
204 .config(&segment_config)
205 .timeout(global_config.global.service.creation_timeout)
206 .open(),
207 "{msg}");
208
209 Ok(Self {
210 memory: MemoryViewType::Static(memory),
211 })
212 }
213
214 pub(crate) fn open_dynamic_segment(
215 segment_name: &FileName,
216 global_config: &config::Config,
217 ) -> Result<Self, SharedMemoryOpenError> {
218 let origin = "DataSegment::open()";
219 let msg =
220 "Unable to open data segment since the underlying shared memory could not be opened.";
221
222 let segment_config = resizable_data_segment_config::<Service>(global_config);
223 let memory = fail!(from origin,
224 when <<Service::ResizableSharedMemory as ResizableSharedMemory<
225 PoolAllocator,
226 Service::SharedMemory,
227 >>::ViewBuilder as NamedConceptBuilder<Service::ResizableSharedMemory>>::new(
228 segment_name,
229 )
230 .config(&segment_config)
231 .open(),
232 "{msg}");
233
234 Ok(Self {
235 memory: MemoryViewType::Dynamic(memory),
236 })
237 }
238
239 pub(crate) fn register_and_translate_offset(
240 &self,
241 offset: PointerOffset,
242 ) -> Result<usize, SharedMemoryOpenError> {
243 match &self.memory {
244 MemoryViewType::Static(memory) => Ok(offset.offset() + memory.payload_start_address()),
245 MemoryViewType::Dynamic(memory) => unsafe {
246 match memory.register_and_translate_offset(offset) {
247 Ok(ptr) => Ok(ptr as usize),
248 Err(e) => {
249 fail!(from self, with e,
250 "Failed to register and translate pointer due to a failure while opening the corresponding shared memory segment ({:?}).",
251 e);
252 }
253 }
254 },
255 }
256 }
257
258 pub(crate) unsafe fn unregister_offset(&self, offset: PointerOffset) {
259 if let MemoryViewType::Dynamic(memory) = &self.memory {
260 memory.unregister_offset(offset);
261 }
262 }
263
264 pub(crate) fn is_dynamic(&self) -> bool {
265 matches!(&self.memory, MemoryViewType::Dynamic(_))
266 }
267}