Skip to content

Commit 1a8e019

Browse files
authored
Merge pull request eclipse-iceoryx#155 from elfenpiff/iox2-153-use-dynamic-storage-everywhere
[eclipse-iceoryx#153] use dynamic storage in shared memory
2 parents 0a03bf7 + b71de04 commit 1a8e019

File tree

24 files changed

+1136
-1001
lines changed

24 files changed

+1136
-1001
lines changed

doc/release-notes/iceoryx2-unreleased.md

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
* Replace `iceoryx2::service::Service` with `iceoryx2::service::Details` [#100](https://github.com/eclipse-iceoryx/iceoryx2/issues/100)
5353
* Remove `'config` lifetime from all structs [#100](https://github.com/eclipse-iceoryx/iceoryx2/issues/100)
5454
* Remove `UniqueIndex` returning method from `iceoryx2-bb-lock-free::mpmc::Container`, cannot be implemented correctly in our context [#116](https://github.com/eclipse-iceoryx/iceoryx2/issues/116)
55+
* All `iceoryx2-cal::shared_memory` implementations use a `DynamicStorage` concept as base [#153](https://github.com/eclipse-iceoryx/iceoryx2/issues/153)
5556

5657
### Workflow
5758

iceoryx2-bb/elementary/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub mod bump_allocator;
1919
pub mod lazy_singleton;
2020
pub mod math;
2121
pub mod owning_pointer;
22+
pub mod package_version;
2223
pub mod pointer_trait;
2324
pub mod relocatable_container;
2425
pub mod relocatable_ptr;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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+
13+
use std::{
14+
fmt::Display,
15+
sync::atomic::{AtomicU64, Ordering},
16+
};
17+
18+
/// Represents the crates version acquired through the internal environment variables set by cargo,
19+
/// ("CARGO_PKG_VERSION_{MAJOR|MINOR|PATCH}").
20+
///
21+
/// # Example
22+
///
23+
/// ```
24+
/// use iceoryx2_bb_elementary::package_version::PackageVersion;
25+
///
26+
/// let version = PackageVersion::get();
27+
///
28+
/// println!("package version: {}", version);
29+
/// println!(" major: {}", version.major());
30+
/// println!(" minor: {}", version.minor());
31+
/// println!(" patch: {}", version.patch());
32+
/// ```
33+
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
34+
pub struct PackageVersion(u64);
35+
36+
impl PackageVersion {
37+
/// Creates a [`PackageVersion`] from a raw encoded u64
38+
pub fn from_u64(value: u64) -> Self {
39+
Self(value)
40+
}
41+
42+
/// Converts the [`PackageVersion`] to an u64
43+
pub fn to_u64(&self) -> u64 {
44+
self.0
45+
}
46+
47+
fn from_version(major: u16, minor: u16, patch: u16) -> Self {
48+
Self(((major as u64) << 32) | ((minor as u64) << 16) | patch as u64)
49+
}
50+
51+
/// Returns the major part of the version
52+
pub fn major(&self) -> u16 {
53+
((self.0 >> 32) & (u16::MAX as u64)) as u16
54+
}
55+
56+
/// Returns the minor part of the version
57+
pub fn minor(&self) -> u16 {
58+
((self.0 >> 16) & (u16::MAX as u64)) as u16
59+
}
60+
61+
/// Returns the patch part of the version
62+
pub fn patch(&self) -> u16 {
63+
((self.0) & (u16::MAX as u64)) as u16
64+
}
65+
66+
/// Returns the current [`PackageVersion`]
67+
pub fn get() -> PackageVersion {
68+
static PACKAGE_VERSION: AtomicU64 = AtomicU64::new(0);
69+
70+
if PACKAGE_VERSION.load(Ordering::Relaxed) == 0 {
71+
let major = option_env!("CARGO_PKG_VERSION_MAJOR")
72+
.and_then(|s| s.parse::<u16>().ok())
73+
.unwrap_or(u16::MAX);
74+
let minor = option_env!("CARGO_PKG_VERSION_MINOR")
75+
.and_then(|s| s.parse::<u16>().ok())
76+
.unwrap_or(u16::MAX);
77+
let patch = option_env!("CARGO_PKG_VERSION_PATCH")
78+
.and_then(|s| s.parse::<u16>().ok())
79+
.unwrap_or(u16::MAX);
80+
81+
PACKAGE_VERSION.store(
82+
PackageVersion::from_version(major, minor, patch).0,
83+
Ordering::Relaxed,
84+
);
85+
}
86+
87+
PackageVersion::from_u64(PACKAGE_VERSION.load(Ordering::Relaxed))
88+
}
89+
}
90+
91+
impl Display for PackageVersion {
92+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93+
write!(f, "{}.{}.{}", self.major(), self.minor(), self.patch())
94+
}
95+
}

iceoryx2-bb/memory/src/pool_allocator.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,12 @@ pub struct PoolAllocator {
7272

7373
impl PoolAllocator {
7474
fn verify_init(&self, source: &str) {
75-
if !self.is_memory_initialized.load(Ordering::Relaxed) {
76-
fatal_panic!(from self, "Undefined behavior when calling \"{}\" and the object is not initialized.", source);
77-
}
75+
debug_assert!(
76+
self.is_memory_initialized.load(Ordering::Relaxed),
77+
"From: {:?}, Undefined behavior when calling \"{}\" and the object is not initialized.",
78+
self,
79+
source
80+
);
7881
}
7982

8083
pub fn number_of_buckets(&self) -> u32 {

iceoryx2-bb/posix/src/shared_memory.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -385,12 +385,17 @@ impl Drop for SharedMemory {
385385
}
386386

387387
if self.has_ownership() {
388-
match Self::shm_unlink(&self.name) {
389-
Ok(_) => {
390-
trace!(from self, "delete");
391-
}
392-
Err(_) => {
393-
error!(from self, "Failed to cleanup shared memory.");
388+
match self.set_permission(Permission::OWNER_ALL) {
389+
Ok(()) => match Self::shm_unlink(&self.name) {
390+
Ok(_) => {
391+
trace!(from self, "delete");
392+
}
393+
Err(_) => {
394+
error!(from self, "Failed to cleanup shared memory.");
395+
}
396+
},
397+
Err(e) => {
398+
error!(from self, "Failed to cleanup shared memory since the permissions could not be adjusted ({:?}).", e);
394399
}
395400
}
396401
}

iceoryx2-cal/src/communication_channel/posix_shared_memory.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ use iceoryx2_bb_lock_free::spsc::safely_overflowing_index_queue::*;
2525
use iceoryx2_bb_log::fail;
2626

2727
type SharedMemory = dynamic_storage::posix_shared_memory::Storage<Management>;
28-
type SharedMemoryBuilder = <SharedMemory as DynamicStorage<Management>>::Builder;
28+
type SharedMemoryBuilder<'builder> =
29+
<SharedMemory as DynamicStorage<Management>>::Builder<'builder>;
2930

3031
#[derive(Debug)]
3132
pub struct Channel {}
@@ -165,15 +166,13 @@ impl CommunicationChannelCreator<usize, Channel> for Creator {
165166
.supplementary_size(SafelyOverflowingIndexQueue::const_memory_size(
166167
self.buffer_size,
167168
))
168-
.create_and_initialize(
169-
Management {
170-
enable_safe_overflow: self.enable_safe_overflow,
171-
index_queue: unsafe {
172-
RelocatableSafelyOverflowingIndexQueue::new_uninit(self.buffer_size)
173-
},
169+
.initializer(|mgmt, allocator| unsafe { mgmt.index_queue.init(allocator).is_ok() })
170+
.create(Management {
171+
enable_safe_overflow: self.enable_safe_overflow,
172+
index_queue: unsafe {
173+
RelocatableSafelyOverflowingIndexQueue::new_uninit(self.buffer_size)
174174
},
175-
|mgmt, allocator| unsafe { mgmt.index_queue.init(allocator).is_ok() },
176-
) {
175+
}) {
177176
Ok(s) => s,
178177
Err(DynamicStorageCreateError::AlreadyExists) => {
179178
fail!(from self, with CommunicationChannelCreateError::AlreadyExists,
@@ -215,7 +214,7 @@ impl CommunicationChannelConnector<usize, Channel> for Connector {
215214

216215
match SharedMemoryBuilder::new(&self.channel_name)
217216
.config(&self.config.into())
218-
.try_open()
217+
.open()
219218
{
220219
Ok(shared_memory) => Ok(Sender { shared_memory }),
221220
Err(DynamicStorageOpenError::DoesNotExist)

iceoryx2-cal/src/dynamic_storage/mod.rs

+43-24
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,33 @@
5454
//! }
5555
//! ```
5656
57-
use std::fmt::Debug;
57+
use std::{fmt::Debug, time::Duration};
5858

59+
use iceoryx2_bb_elementary::enum_gen;
5960
use iceoryx2_bb_memory::bump_allocator::BumpAllocator;
6061
use iceoryx2_bb_system_types::file_name::*;
62+
use tiny_fn::tiny_fn;
6163

6264
use crate::static_storage::file::{NamedConcept, NamedConceptBuilder, NamedConceptMgmt};
6365

66+
tiny_fn! {
67+
pub(crate) struct Initializer<T> = FnMut(value: &mut T, allocator: &mut BumpAllocator) -> bool;
68+
}
69+
70+
impl<T> Debug for Initializer<'_, T> {
71+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72+
write!(f, "")
73+
}
74+
}
75+
6476
pub mod posix_shared_memory;
6577
pub mod process_local;
6678

6779
/// Describes failures when creating a new [`DynamicStorage`]
6880
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
6981
pub enum DynamicStorageCreateError {
7082
AlreadyExists,
71-
Creation,
72-
Write,
83+
InsufficientPermissions,
7384
InitializationFailed,
7485
InternalError,
7586
}
@@ -78,13 +89,20 @@ pub enum DynamicStorageCreateError {
7889
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
7990
pub enum DynamicStorageOpenError {
8091
DoesNotExist,
81-
Open,
8292
InitializationNotYetFinalized,
93+
VersionMismatch,
8394
InternalError,
8495
}
8596

97+
enum_gen! {
98+
DynamicStorageOpenOrCreateError
99+
mapping:
100+
DynamicStorageOpenError,
101+
DynamicStorageCreateError
102+
}
103+
86104
/// Builder for the [`DynamicStorage`]. T is not allowed to implement the [`Drop`] trait.
87-
pub trait DynamicStorageBuilder<T: Send + Sync, D: DynamicStorage<T>>:
105+
pub trait DynamicStorageBuilder<'builder, T: Send + Sync, D: DynamicStorage<T>>:
88106
Debug + Sized + NamedConceptBuilder<D>
89107
{
90108
/// Defines if a newly created [`DynamicStorage`] owns the underlying resources
@@ -93,37 +111,38 @@ pub trait DynamicStorageBuilder<T: Send + Sync, D: DynamicStorage<T>>:
93111
/// Sets the size of the supplementary data
94112
fn supplementary_size(self, value: usize) -> Self;
95113

114+
/// The timeout defines how long the [`DynamicStorageBuilder`] should wait for
115+
/// [`DynamicStorageBuilder::create()`]
116+
/// to finialize the initialization. This is required when the [`DynamicStorage`] is
117+
/// created and initialized concurrently from another process.
118+
/// By default it is set to [`Duration::ZERO`] for no timeout.
119+
fn timeout(self, value: Duration) -> Self;
120+
121+
/// Before the construction is finalized the initializer is called
122+
/// with a mutable reference to the new value and a mutable reference to a bump allocator
123+
/// which provides access to the supplementary memory. If the initialization failed it
124+
/// shall return false, otherwise true.
125+
fn initializer<F: FnMut(&mut T, &mut BumpAllocator) -> bool + 'builder>(self, value: F)
126+
-> Self;
127+
96128
/// Creates a new [`DynamicStorage`]. The returned object has the ownership of the
97129
/// [`DynamicStorage`] and when it goes out of scope the underlying resources shall be
98130
/// removed without corrupting already opened [`DynamicStorage`]s.
99-
fn create(self, initial_value: T) -> Result<D, DynamicStorageCreateError> {
100-
self.create_and_initialize(initial_value, |_, _| true)
101-
}
102-
103-
/// Creates a new [`DynamicStorage`]. Before the construction is finalized the initializer
104-
/// with a mutable reference to the new value and a mutable reference to a bump allocator
105-
/// which provides access to the supplementary memory.
106-
fn create_and_initialize<F: FnOnce(&mut T, &mut BumpAllocator) -> bool>(
107-
self,
108-
initial_value: T,
109-
initializer: F,
110-
) -> Result<D, DynamicStorageCreateError>;
131+
fn create(self, initial_value: T) -> Result<D, DynamicStorageCreateError>;
111132

112133
/// Opens a [`DynamicStorage`]. The implementation must ensure that a [`DynamicStorage`]
113-
/// which is in the midst of creation cannot be opened.
134+
/// which is in the midst of creation cannot be opened. If the [`DynamicStorage`] does not
135+
/// exist or is not initialized it fails.
114136
fn open(self) -> Result<D, DynamicStorageOpenError>;
115137

116-
/// Opens a [`DynamicStorage`]. The implementation must ensure that a [`DynamicStorage`]
117-
/// which is in the midst of creation cannot be opened. In contrast to the counterpart
118-
/// [`DynamicStorageBuilder::open()`] it does not print an error message when the channel
119-
/// does not exist or is not yet finalized.
120-
fn try_open(self) -> Result<D, DynamicStorageOpenError>;
138+
/// Opens the [`DynamicStorage`] if it exists, otherwise it creates it.
139+
fn open_or_create(self, initial_value: T) -> Result<D, DynamicStorageOpenOrCreateError>;
121140
}
122141

123142
/// Is being built by the [`DynamicStorageBuilder`]. The [`DynamicStorage`] trait shall provide
124143
/// inter-process access to a modifyable piece of memory identified by some name.
125144
pub trait DynamicStorage<T: Send + Sync>: Sized + Debug + NamedConceptMgmt + NamedConcept {
126-
type Builder: DynamicStorageBuilder<T, Self>;
145+
type Builder<'builder>: DynamicStorageBuilder<'builder, T, Self>;
127146

128147
/// Returns if the dynamic storage supports persistency, meaning that the underlying OS
129148
/// resource remain even when every dynamic storage instance in every process was removed.

0 commit comments

Comments
 (0)