Skip to content

Commit c875ed1

Browse files
committed
[eclipse-iceoryx#497] New segments are created when out-of-memory
1 parent 7f4ec0b commit c875ed1

File tree

6 files changed

+120
-28
lines changed

6 files changed

+120
-28
lines changed

iceoryx2-cal/src/resizable_shared_memory/dynamic.rs

Lines changed: 93 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111
// SPDX-License-Identifier: Apache-2.0 OR MIT
1212

1313
use std::alloc::Layout;
14+
use std::cell::UnsafeCell;
1415
use std::sync::atomic::Ordering;
1516
use std::time::Duration;
1617
use std::{fmt::Debug, marker::PhantomData};
1718

18-
use crate::shared_memory::ShmPointer;
19+
use crate::shared_memory::{AllocationStrategy, ShmPointer};
1920
use crate::shared_memory::{
2021
PointerOffset, SharedMemory, SharedMemoryBuilder, SharedMemoryCreateError,
2122
SharedMemoryOpenError, ShmAllocator,
@@ -41,6 +42,8 @@ struct BuilderConfig<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
4142
base_name: FileName,
4243
shm: Shm::Configuration,
4344
allocator_config_hint: Allocator::Configuration,
45+
allocation_strategy: AllocationStrategy,
46+
has_ownership: bool,
4447
shm_builder_timeout: Duration,
4548
max_number_of_chunks_hint: usize,
4649
}
@@ -50,7 +53,6 @@ pub struct DynamicBuilder<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
5053
where
5154
Allocator: Debug,
5255
{
53-
builder: Shm::Builder,
5456
config: BuilderConfig<Allocator, Shm>,
5557
}
5658

@@ -63,9 +65,10 @@ impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
6365
.push_bytes(b"__0")
6466
.expect("Adding __0 results in a valid file name");
6567
Self {
66-
builder: Shm::Builder::new(name),
6768
config: BuilderConfig {
6869
base_name: *name,
70+
has_ownership: true,
71+
allocation_strategy: AllocationStrategy::default(),
6972
shm_builder_timeout: Duration::ZERO,
7073
allocator_config_hint: Allocator::Configuration::default(),
7174
shm: Shm::Configuration::default(),
@@ -92,7 +95,7 @@ where
9295
Shm::Builder: Debug,
9396
{
9497
fn has_ownership(mut self, value: bool) -> Self {
95-
self.builder = self.builder.has_ownership(value);
98+
self.config.has_ownership = value;
9699
self
97100
}
98101

@@ -106,6 +109,11 @@ where
106109
self
107110
}
108111

112+
fn allocation_strategy(mut self, value: AllocationStrategy) -> Self {
113+
self.config.allocation_strategy = value;
114+
self
115+
}
116+
109117
fn timeout(mut self, value: Duration) -> Self {
110118
self.config.shm_builder_timeout = value;
111119
self
@@ -118,10 +126,7 @@ where
118126
);
119127

120128
let origin = format!("{:?}", self);
121-
let shm = fail!(from origin, when self
122-
.builder
123-
.size(initial_size)
124-
.create(&self.config.allocator_config_hint),
129+
let shm = fail!(from origin, when DynamicMemory::create_segment(&self.config, 0, initial_size),
125130
"Unable to create ResizableSharedMemory since the underlying shared memory could not be created.");
126131

127132
let mut shared_memory_map = SlotMap::new(MAX_DATASEGMENTS);
@@ -130,19 +135,19 @@ where
130135
.expect("MAX_DATASEGMENTS is greater or equal 1");
131136

132137
Ok(DynamicMemory {
133-
builder_config: self.config,
134-
shared_memory_map,
135-
current_idx,
138+
state: UnsafeCell::new(InternalState {
139+
builder_config: self.config,
140+
shared_memory_map,
141+
current_idx,
142+
}),
136143
has_ownership: IoxAtomicBool::new(true),
137144
_data: PhantomData,
138145
})
139146
}
140147

141148
fn open(self) -> Result<DynamicView<Allocator, Shm>, SharedMemoryOpenError> {
142149
let origin = format!("{:?}", self);
143-
let shm = fail!(from origin, when self
144-
.builder
145-
.open(),
150+
let shm = fail!(from origin, when DynamicMemory::open_segment(&self.config, 0),
146151
"Unable to open ResizableSharedMemoryView since the underlying shared memory could not be opened.");
147152

148153
let mut shared_memory_map = SlotMap::new(MAX_DATASEGMENTS);
@@ -191,10 +196,15 @@ impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
191196
}
192197

193198
#[derive(Debug)]
194-
pub struct DynamicMemory<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
199+
struct InternalState<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
195200
builder_config: BuilderConfig<Allocator, Shm>,
196201
shared_memory_map: SlotMap<Shm>,
197202
current_idx: SlotMapKey,
203+
}
204+
205+
#[derive(Debug)]
206+
pub struct DynamicMemory<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
207+
state: UnsafeCell<InternalState<Allocator, Shm>>,
198208
has_ownership: IoxAtomicBool,
199209
_data: PhantomData<Allocator>,
200210
}
@@ -203,7 +213,7 @@ impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> NamedConcept
203213
for DynamicMemory<Allocator, Shm>
204214
{
205215
fn name(&self) -> &FileName {
206-
&self.builder_config.base_name
216+
unsafe { &(&*self.state.get()).builder_config.base_name }
207217
}
208218
}
209219

@@ -236,8 +246,62 @@ impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> NamedConceptMgmt
236246
}
237247

238248
impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> DynamicMemory<Allocator, Shm> {
239-
fn create_new_segment(&self, layout: Layout) -> Result<(), SharedMemoryCreateError> {
240-
todo!()
249+
fn state_mut(&self) -> &mut InternalState<Allocator, Shm> {
250+
unsafe { &mut *self.state.get() }
251+
}
252+
253+
fn create_segment(
254+
config: &BuilderConfig<Allocator, Shm>,
255+
segment_id: u8,
256+
payload_size: usize,
257+
) -> Result<Shm, SharedMemoryCreateError> {
258+
Self::segment_builder(config, segment_id)
259+
.size(payload_size)
260+
.create(&config.allocator_config_hint)
261+
}
262+
263+
fn open_segment(
264+
config: &BuilderConfig<Allocator, Shm>,
265+
segment_id: u8,
266+
) -> Result<Shm, SharedMemoryOpenError> {
267+
Self::segment_builder(config, segment_id).open()
268+
}
269+
270+
fn segment_builder(config: &BuilderConfig<Allocator, Shm>, segment_id: u8) -> Shm::Builder {
271+
let msg = "This should never happen! Unable to create additional shared memory segment since it would result in an invalid shared memory name.";
272+
let mut adjusted_name = config.base_name;
273+
fatal_panic!(from config, when adjusted_name.push_bytes(b"__"), "{msg}");
274+
fatal_panic!(from config, when adjusted_name.push_bytes(segment_id.to_string().as_bytes()), "{msg}");
275+
Shm::Builder::new(&adjusted_name)
276+
.has_ownership(config.has_ownership)
277+
.timeout(config.shm_builder_timeout)
278+
.config(&config.shm)
279+
}
280+
281+
fn create_resized_segment(
282+
&self,
283+
shm: &Shm,
284+
layout: Layout,
285+
segment_id: u8,
286+
) -> Result<(), SharedMemoryCreateError> {
287+
let state = self.state_mut();
288+
let adjusted_segment_setup = shm
289+
.allocator()
290+
.resize_hint(layout, state.builder_config.allocation_strategy);
291+
let segment_id = segment_id + 1;
292+
293+
state.builder_config.allocator_config_hint = adjusted_segment_setup.config;
294+
let shm = Self::create_segment(
295+
&state.builder_config,
296+
segment_id,
297+
adjusted_segment_setup.payload_size,
298+
)?;
299+
300+
let key = SlotMapKey::new(segment_id as usize);
301+
state.shared_memory_map.insert_at(key, shm);
302+
state.current_idx = key;
303+
304+
Ok(())
241305
}
242306
}
243307

@@ -250,12 +314,18 @@ where
250314
type View = DynamicView<Allocator, Shm>;
251315

252316
fn allocate(&self, layout: Layout) -> Result<ShmPointer, ResizableShmAllocationError> {
317+
let state = self.state_mut();
318+
253319
loop {
254-
match self.shared_memory_map.get(self.current_idx) {
255-
Some(shm) => match shm.allocate(layout) {
320+
match state.shared_memory_map.get(state.current_idx) {
321+
Some(ref shm) => match shm.allocate(layout) {
256322
Ok(ptr) => return Ok(ptr),
257323
Err(ShmAllocationError::AllocationError(AllocationError::OutOfMemory)) => {
258-
self.create_new_segment(layout)?;
324+
self.create_resized_segment(
325+
shm,
326+
layout,
327+
state.current_idx.value() as u8 + 1,
328+
)?;
259329
}
260330
Err(e) => return Err(e.into()),
261331
},
@@ -266,7 +336,8 @@ where
266336
}
267337

268338
unsafe fn deallocate(&self, offset: PointerOffset, layout: Layout) {
269-
match self.shared_memory_map.get(self.current_idx) {
339+
let state = self.state_mut();
340+
match state.shared_memory_map.get(state.current_idx) {
270341
Some(shm) => shm.deallocate(offset, layout),
271342
None => fatal_panic!(from self,
272343
"This should never happen! Current shared memory segment is not available!"),

iceoryx2-cal/src/resizable_shared_memory/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use iceoryx2_bb_elementary::enum_gen;
1919

2020
use crate::named_concept::*;
2121
use crate::shared_memory::{
22-
SharedMemory, SharedMemoryCreateError, SharedMemoryOpenError, ShmPointer,
22+
AllocationStrategy, SharedMemory, SharedMemoryCreateError, SharedMemoryOpenError, ShmPointer,
2323
};
2424
use crate::shm_allocator::{PointerOffset, ShmAllocationError, ShmAllocator};
2525

@@ -45,6 +45,8 @@ pub trait ResizableSharedMemoryBuilder<
4545

4646
fn max_number_of_chunks_hint(self, value: usize) -> Self;
4747

48+
fn allocation_strategy(self, value: AllocationStrategy) -> Self;
49+
4850
/// The timeout defines how long the [`SharedMemoryBuilder`] should wait for
4951
/// [`SharedMemoryBuilder::create()`] to finialize
5052
/// the initialization. This is required when the [`SharedMemory`] is created and initialized

iceoryx2-cal/src/shared_memory/common.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,15 @@ pub mod details {
383383
}
384384
}
385385

386+
impl<Allocator: ShmAllocator + Debug, Storage: DynamicStorage<AllocatorDetails<Allocator>>>
387+
crate::shared_memory::details::SharedMemoryExpertAPI<Allocator>
388+
for Memory<Allocator, Storage>
389+
{
390+
fn allocator(&self) -> &Allocator {
391+
unsafe { self.storage.get().allocator.assume_init_ref() }
392+
}
393+
}
394+
386395
impl<Allocator: ShmAllocator + Debug, Storage: DynamicStorage<AllocatorDetails<Allocator>>>
387396
crate::shared_memory::SharedMemory<Allocator> for Memory<Allocator, Storage>
388397
{

iceoryx2-cal/src/shared_memory/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ pub struct ShmPointer {
9595
pub data_ptr: *mut u8,
9696
}
9797

98+
#[doc(hidden)]
99+
pub(crate) mod details {
100+
use super::*;
101+
102+
pub trait SharedMemoryExpertAPI<Allocator: ShmAllocator> {
103+
fn allocator(&self) -> &Allocator;
104+
}
105+
}
106+
98107
/// Creates [`SharedMemory`].
99108
pub trait SharedMemoryBuilder<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>:
100109
NamedConceptBuilder<Shm>
@@ -126,7 +135,7 @@ pub trait SharedMemoryBuilder<Allocator: ShmAllocator, Shm: SharedMemory<Allocat
126135
/// Abstract concept of a memory shared between multiple processes. Can be created with the
127136
/// [`SharedMemoryBuilder`].
128137
pub trait SharedMemory<Allocator: ShmAllocator>:
129-
Sized + Debug + NamedConcept + NamedConceptMgmt
138+
Sized + Debug + NamedConcept + NamedConceptMgmt + details::SharedMemoryExpertAPI<Allocator>
130139
{
131140
type Builder: SharedMemoryBuilder<Allocator, Self>;
132141

iceoryx2-cal/src/shm_allocator/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ enum_gen! { ShmAllocationError
4545
AllocationError
4646
}
4747

48-
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
48+
#[derive(Clone, Copy, Eq, PartialEq, Debug, Default)]
4949
pub enum AllocationStrategy {
5050
BestFit,
51+
#[default]
5152
PowerOfTwo,
5253
}
5354

@@ -58,8 +59,8 @@ pub enum ShmAllocatorInitError {
5859
}
5960

6061
pub struct ResizeHint<Config: ShmAllocatorConfig> {
61-
payload_size: usize,
62-
config: Config,
62+
pub(crate) payload_size: usize,
63+
pub(crate) config: Config,
6364
}
6465

6566
/// Every allocator implementation must be relocatable. The allocator itself must be stored either

iceoryx2-cal/tests/resizable_shared_memory_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
mod resizable_shared_memory {
1515
use std::alloc::Layout;
1616

17+
use iceoryx2_bb_log::set_log_level;
1718
use iceoryx2_bb_testing::assert_that;
1819
use iceoryx2_cal::named_concept::*;
1920
use iceoryx2_cal::resizable_shared_memory::{self, *};
@@ -58,7 +59,6 @@ mod resizable_shared_memory {
5859
assert_that!(unsafe{ *ptr_view }, eq test_value_2);
5960
}
6061

61-
#[ignore]
6262
#[test]
6363
fn allocate_more_than_hinted_works<
6464
Shm: SharedMemory<DefaultAllocator>,

0 commit comments

Comments
 (0)