Skip to content

Commit

Permalink
Merge pull request #155 from elfenpiff/iox2-153-use-dynamic-storage-e…
Browse files Browse the repository at this point in the history
…verywhere

[#153] use dynamic storage in shared memory
  • Loading branch information
elfenpiff authored Mar 19, 2024
2 parents 0a03bf7 + b71de04 commit 1a8e019
Show file tree
Hide file tree
Showing 24 changed files with 1,136 additions and 1,001 deletions.
1 change: 1 addition & 0 deletions doc/release-notes/iceoryx2-unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
* Replace `iceoryx2::service::Service` with `iceoryx2::service::Details` [#100](https://github.com/eclipse-iceoryx/iceoryx2/issues/100)
* Remove `'config` lifetime from all structs [#100](https://github.com/eclipse-iceoryx/iceoryx2/issues/100)
* 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)
* All `iceoryx2-cal::shared_memory` implementations use a `DynamicStorage` concept as base [#153](https://github.com/eclipse-iceoryx/iceoryx2/issues/153)

### Workflow

Expand Down
1 change: 1 addition & 0 deletions iceoryx2-bb/elementary/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod bump_allocator;
pub mod lazy_singleton;
pub mod math;
pub mod owning_pointer;
pub mod package_version;
pub mod pointer_trait;
pub mod relocatable_container;
pub mod relocatable_ptr;
Expand Down
95 changes: 95 additions & 0 deletions iceoryx2-bb/elementary/src/package_version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) 2024 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Apache Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

use std::{
fmt::Display,
sync::atomic::{AtomicU64, Ordering},
};

/// Represents the crates version acquired through the internal environment variables set by cargo,
/// ("CARGO_PKG_VERSION_{MAJOR|MINOR|PATCH}").
///
/// # Example
///
/// ```
/// use iceoryx2_bb_elementary::package_version::PackageVersion;
///
/// let version = PackageVersion::get();
///
/// println!("package version: {}", version);
/// println!(" major: {}", version.major());
/// println!(" minor: {}", version.minor());
/// println!(" patch: {}", version.patch());
/// ```
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct PackageVersion(u64);

impl PackageVersion {
/// Creates a [`PackageVersion`] from a raw encoded u64
pub fn from_u64(value: u64) -> Self {
Self(value)
}

/// Converts the [`PackageVersion`] to an u64
pub fn to_u64(&self) -> u64 {
self.0
}

fn from_version(major: u16, minor: u16, patch: u16) -> Self {
Self(((major as u64) << 32) | ((minor as u64) << 16) | patch as u64)
}

/// Returns the major part of the version
pub fn major(&self) -> u16 {
((self.0 >> 32) & (u16::MAX as u64)) as u16
}

/// Returns the minor part of the version
pub fn minor(&self) -> u16 {
((self.0 >> 16) & (u16::MAX as u64)) as u16
}

/// Returns the patch part of the version
pub fn patch(&self) -> u16 {
((self.0) & (u16::MAX as u64)) as u16
}

/// Returns the current [`PackageVersion`]
pub fn get() -> PackageVersion {
static PACKAGE_VERSION: AtomicU64 = AtomicU64::new(0);

if PACKAGE_VERSION.load(Ordering::Relaxed) == 0 {
let major = option_env!("CARGO_PKG_VERSION_MAJOR")
.and_then(|s| s.parse::<u16>().ok())
.unwrap_or(u16::MAX);
let minor = option_env!("CARGO_PKG_VERSION_MINOR")
.and_then(|s| s.parse::<u16>().ok())
.unwrap_or(u16::MAX);
let patch = option_env!("CARGO_PKG_VERSION_PATCH")
.and_then(|s| s.parse::<u16>().ok())
.unwrap_or(u16::MAX);

PACKAGE_VERSION.store(
PackageVersion::from_version(major, minor, patch).0,
Ordering::Relaxed,
);
}

PackageVersion::from_u64(PACKAGE_VERSION.load(Ordering::Relaxed))
}
}

impl Display for PackageVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}.{}.{}", self.major(), self.minor(), self.patch())
}
}
9 changes: 6 additions & 3 deletions iceoryx2-bb/memory/src/pool_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,12 @@ pub struct PoolAllocator {

impl PoolAllocator {
fn verify_init(&self, source: &str) {
if !self.is_memory_initialized.load(Ordering::Relaxed) {
fatal_panic!(from self, "Undefined behavior when calling \"{}\" and the object is not initialized.", source);
}
debug_assert!(
self.is_memory_initialized.load(Ordering::Relaxed),
"From: {:?}, Undefined behavior when calling \"{}\" and the object is not initialized.",
self,
source
);
}

pub fn number_of_buckets(&self) -> u32 {
Expand Down
17 changes: 11 additions & 6 deletions iceoryx2-bb/posix/src/shared_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,12 +385,17 @@ impl Drop for SharedMemory {
}

if self.has_ownership() {
match Self::shm_unlink(&self.name) {
Ok(_) => {
trace!(from self, "delete");
}
Err(_) => {
error!(from self, "Failed to cleanup shared memory.");
match self.set_permission(Permission::OWNER_ALL) {
Ok(()) => match Self::shm_unlink(&self.name) {
Ok(_) => {
trace!(from self, "delete");
}
Err(_) => {
error!(from self, "Failed to cleanup shared memory.");
}
},
Err(e) => {
error!(from self, "Failed to cleanup shared memory since the permissions could not be adjusted ({:?}).", e);
}
}
}
Expand Down
19 changes: 9 additions & 10 deletions iceoryx2-cal/src/communication_channel/posix_shared_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ use iceoryx2_bb_lock_free::spsc::safely_overflowing_index_queue::*;
use iceoryx2_bb_log::fail;

type SharedMemory = dynamic_storage::posix_shared_memory::Storage<Management>;
type SharedMemoryBuilder = <SharedMemory as DynamicStorage<Management>>::Builder;
type SharedMemoryBuilder<'builder> =
<SharedMemory as DynamicStorage<Management>>::Builder<'builder>;

#[derive(Debug)]
pub struct Channel {}
Expand Down Expand Up @@ -165,15 +166,13 @@ impl CommunicationChannelCreator<usize, Channel> for Creator {
.supplementary_size(SafelyOverflowingIndexQueue::const_memory_size(
self.buffer_size,
))
.create_and_initialize(
Management {
enable_safe_overflow: self.enable_safe_overflow,
index_queue: unsafe {
RelocatableSafelyOverflowingIndexQueue::new_uninit(self.buffer_size)
},
.initializer(|mgmt, allocator| unsafe { mgmt.index_queue.init(allocator).is_ok() })
.create(Management {
enable_safe_overflow: self.enable_safe_overflow,
index_queue: unsafe {
RelocatableSafelyOverflowingIndexQueue::new_uninit(self.buffer_size)
},
|mgmt, allocator| unsafe { mgmt.index_queue.init(allocator).is_ok() },
) {
}) {
Ok(s) => s,
Err(DynamicStorageCreateError::AlreadyExists) => {
fail!(from self, with CommunicationChannelCreateError::AlreadyExists,
Expand Down Expand Up @@ -215,7 +214,7 @@ impl CommunicationChannelConnector<usize, Channel> for Connector {

match SharedMemoryBuilder::new(&self.channel_name)
.config(&self.config.into())
.try_open()
.open()
{
Ok(shared_memory) => Ok(Sender { shared_memory }),
Err(DynamicStorageOpenError::DoesNotExist)
Expand Down
67 changes: 43 additions & 24 deletions iceoryx2-cal/src/dynamic_storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,33 @@
//! }
//! ```
use std::fmt::Debug;
use std::{fmt::Debug, time::Duration};

use iceoryx2_bb_elementary::enum_gen;
use iceoryx2_bb_memory::bump_allocator::BumpAllocator;
use iceoryx2_bb_system_types::file_name::*;
use tiny_fn::tiny_fn;

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

tiny_fn! {
pub(crate) struct Initializer<T> = FnMut(value: &mut T, allocator: &mut BumpAllocator) -> bool;
}

impl<T> Debug for Initializer<'_, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "")
}
}

pub mod posix_shared_memory;
pub mod process_local;

/// Describes failures when creating a new [`DynamicStorage`]
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
pub enum DynamicStorageCreateError {
AlreadyExists,
Creation,
Write,
InsufficientPermissions,
InitializationFailed,
InternalError,
}
Expand All @@ -78,13 +89,20 @@ pub enum DynamicStorageCreateError {
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
pub enum DynamicStorageOpenError {
DoesNotExist,
Open,
InitializationNotYetFinalized,
VersionMismatch,
InternalError,
}

enum_gen! {
DynamicStorageOpenOrCreateError
mapping:
DynamicStorageOpenError,
DynamicStorageCreateError
}

/// Builder for the [`DynamicStorage`]. T is not allowed to implement the [`Drop`] trait.
pub trait DynamicStorageBuilder<T: Send + Sync, D: DynamicStorage<T>>:
pub trait DynamicStorageBuilder<'builder, T: Send + Sync, D: DynamicStorage<T>>:
Debug + Sized + NamedConceptBuilder<D>
{
/// Defines if a newly created [`DynamicStorage`] owns the underlying resources
Expand All @@ -93,37 +111,38 @@ pub trait DynamicStorageBuilder<T: Send + Sync, D: DynamicStorage<T>>:
/// Sets the size of the supplementary data
fn supplementary_size(self, value: usize) -> Self;

/// The timeout defines how long the [`DynamicStorageBuilder`] should wait for
/// [`DynamicStorageBuilder::create()`]
/// to finialize the initialization. This is required when the [`DynamicStorage`] is
/// created and initialized concurrently from another process.
/// By default it is set to [`Duration::ZERO`] for no timeout.
fn timeout(self, value: Duration) -> Self;

/// Before the construction is finalized the initializer is called
/// with a mutable reference to the new value and a mutable reference to a bump allocator
/// which provides access to the supplementary memory. If the initialization failed it
/// shall return false, otherwise true.
fn initializer<F: FnMut(&mut T, &mut BumpAllocator) -> bool + 'builder>(self, value: F)
-> Self;

/// Creates a new [`DynamicStorage`]. The returned object has the ownership of the
/// [`DynamicStorage`] and when it goes out of scope the underlying resources shall be
/// removed without corrupting already opened [`DynamicStorage`]s.
fn create(self, initial_value: T) -> Result<D, DynamicStorageCreateError> {
self.create_and_initialize(initial_value, |_, _| true)
}

/// Creates a new [`DynamicStorage`]. Before the construction is finalized the initializer
/// with a mutable reference to the new value and a mutable reference to a bump allocator
/// which provides access to the supplementary memory.
fn create_and_initialize<F: FnOnce(&mut T, &mut BumpAllocator) -> bool>(
self,
initial_value: T,
initializer: F,
) -> Result<D, DynamicStorageCreateError>;
fn create(self, initial_value: T) -> Result<D, DynamicStorageCreateError>;

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

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

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

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

0 comments on commit 1a8e019

Please sign in to comment.