Skip to main content

iceoryx2_cal/dynamic_storage/
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
13//! Traits that provide modifyable memory which can be accessed by multiple processes
14//! identified by a name.
15//!
16//! A [`DynamicStorage`] has to fulfill the following contract:
17//!  * zero sized names are not valid
18//!  * **unique:** multiple [`DynamicStorage`]s with the same cannot be created
19//!  * non-existing [`DynamicStorage`]s cannot be opened
20//!
21//! The contract is verified by the corresponding unit tests. Every [`DynamicStorage`] must
22//! pass the test.
23//!
24//! **Important:** It is not the task of the [`DynamicStorage`] to ensure a thread-safe access to
25//! the underlying object. If the [`DynamicStorage`] is used in an inter-process environment every
26//! access must be considered as a concurrent access!
27//!
28//! # Example
29//!
30//! ```
31//! use iceoryx2_bb_posix::access_mode::AccessMode;
32//! use iceoryx2_bb_system_types::file_name::FileName;
33//! use iceoryx2_bb_container::semantic_string::SemanticString;
34//! use iceoryx2_cal::dynamic_storage::*;
35//! use iceoryx2_cal::named_concept::*;
36//! use core::sync::atomic::{AtomicU64, Ordering};
37//!
38//! // the following two functions can be implemented in different processes
39//! fn process_one<Storage: DynamicStorage<AtomicU64>>() {
40//!     let storage_name = FileName::new(b"myStorageName").unwrap();
41//!     let mut storage = Storage::Builder::new(&storage_name)
42//!                         .create(AtomicU64::new(873)).unwrap();
43//!
44//!     println!("Created storage {}", storage.name());
45//!     storage.get().store(991, Ordering::Relaxed);
46//! }
47//!
48//! fn process_two<Storage: DynamicStorage<AtomicU64>>() {
49//!     let storage_name = FileName::new(b"myStorageName").unwrap();
50//!     let mut storage = Storage::Builder::new(&storage_name)
51//!                         .open(AccessMode::ReadWrite).unwrap();
52//!
53//!     println!("Opened storage {}", storage.name());
54//!     println!("Current value {}", storage.get().swap(1001, Ordering::Relaxed));
55//! }
56//! ```
57
58use core::{fmt::Debug, time::Duration};
59
60use iceoryx2_bb_elementary::enum_gen;
61use iceoryx2_bb_elementary_traits::testing::abandonable::Abandonable;
62use iceoryx2_bb_memory::bump_allocator::BumpAllocator;
63use iceoryx2_bb_posix::file::AccessMode;
64use iceoryx2_bb_system_types::file_name::*;
65use tiny_fn::tiny_fn;
66
67use crate::static_storage::file::{NamedConcept, NamedConceptBuilder, NamedConceptMgmt};
68
69tiny_fn! {
70    /// The callback called to initialize the data inside the [`DynamicStorage`]
71    pub struct Initializer<T> = FnMut(value: &mut T, allocator: &mut BumpAllocator) -> bool;
72}
73
74impl<T> Debug for Initializer<'_, T> {
75    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76        write!(f, "")
77    }
78}
79
80#[doc(hidden)]
81pub mod dynamic_storage_configuration;
82pub mod file;
83pub mod posix_shared_memory;
84pub mod process_local;
85pub mod recommended;
86
87/// Describes failures when creating a new [`DynamicStorage`]
88#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
89pub enum DynamicStorageCreateError {
90    AlreadyExists,
91    InsufficientPermissions,
92    InitializationFailed,
93    InternalError,
94}
95
96impl core::fmt::Display for DynamicStorageCreateError {
97    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
98        write!(f, "DynamicStorageCreateError::{self:?}")
99    }
100}
101
102impl core::error::Error for DynamicStorageCreateError {}
103
104/// Describes failures when opening a new [`DynamicStorage`]
105#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
106pub enum DynamicStorageOpenError {
107    DoesNotExist,
108    InitializationNotYetFinalized,
109    VersionMismatch,
110    InternalError,
111}
112
113impl core::fmt::Display for DynamicStorageOpenError {
114    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115        write!(f, "DynamicStorageOpenError::{self:?}")
116    }
117}
118
119impl core::error::Error for DynamicStorageOpenError {}
120
121enum_gen! {
122    DynamicStorageOpenOrCreateError
123  mapping:
124    DynamicStorageOpenError,
125    DynamicStorageCreateError
126}
127
128/// Builder for the [`DynamicStorage`]. T is not allowed to implement the [`Drop`] trait.
129pub trait DynamicStorageBuilder<'builder, T: Send + Sync, D: DynamicStorage<T>>:
130    Debug + Sized + NamedConceptBuilder<D>
131{
132    /// Defines if `T::Drop` shall be called when the [`DynamicStorage`] is removed. The default
133    /// is [`true`].
134    fn call_drop_on_destruction(self, value: bool) -> Self;
135
136    /// Defines if a newly created [`DynamicStorage`] owns the underlying resources. The default
137    /// is [`true`].
138    fn has_ownership(self, value: bool) -> Self;
139
140    /// Sets the size of the supplementary data. Only relevant when it is newly created otherwise
141    /// the already initialized [`DynamicStorage`] with the full size is used.
142    fn supplementary_size(self, value: usize) -> Self;
143
144    /// The timeout defines how long the [`DynamicStorageBuilder`] should wait for
145    /// [`DynamicStorageBuilder::create()`]
146    /// to finialize the initialization. This is required when the [`DynamicStorage`] is
147    /// created and initialized concurrently from another process.
148    /// By default it is set to [`Duration::ZERO`] for no timeout.
149    fn timeout(self, value: Duration) -> Self;
150
151    /// Before the construction is finalized the initializer is called
152    /// with a mutable reference to the new value and a mutable reference to a bump allocator
153    /// which provides access to the supplementary memory. If the initialization failed it
154    /// shall return false, otherwise true.
155    fn initializer<F: FnMut(&mut T, &mut BumpAllocator) -> bool + 'builder>(self, value: F)
156    -> Self;
157
158    /// Creates a new [`DynamicStorage`]. The returned object has the ownership of the
159    /// [`DynamicStorage`] and when it goes out of scope the underlying resources shall be
160    /// removed without corrupting already opened [`DynamicStorage`]s.
161    fn create(self, initial_value: T) -> Result<D, DynamicStorageCreateError>;
162
163    /// Opens a [`DynamicStorage`]. The implementation must ensure that a [`DynamicStorage`]
164    /// which is in the midst of creation cannot be opened. If the [`DynamicStorage`] does not
165    /// exist or is not initialized it fails.
166    fn open(self, access_mode: AccessMode) -> Result<D, DynamicStorageOpenError>;
167
168    /// Opens the [`DynamicStorage`] if it exists, otherwise it creates it.
169    fn open_or_create(self, initial_value: T) -> Result<D, DynamicStorageOpenOrCreateError>;
170}
171
172/// Is being built by the [`DynamicStorageBuilder`]. The [`DynamicStorage`] trait shall provide
173/// inter-process access to a modifyable piece of memory identified by some name.
174pub trait DynamicStorage<T: Send + Sync>:
175    Sized + Debug + NamedConceptMgmt + NamedConcept + Send + Sync + Abandonable
176{
177    type Builder<'builder>: DynamicStorageBuilder<'builder, T, Self>;
178
179    /// Returns if the [`DynamicStorage`] supports persistency, meaning that the underlying OS
180    /// resource remain even when every [`DynamicStorage`] instance in every process was removed.
181    fn does_support_persistency() -> bool;
182
183    /// Returns true if the storage holds the ownership, otherwise false.
184    fn has_ownership(&self) -> bool;
185
186    /// Releases the ownership of the [`DynamicStorage`]. When the object goes out of scope it is
187    /// no longer removed.
188    fn release_ownership(&self);
189
190    /// Acquires the ownership of the [`DynamicStorage`]. When the object goes out of scope the
191    /// underlying resources will be removed.
192    fn acquire_ownership(&self);
193
194    /// Returns a const reference to the underlying object. It is const since the [`DynamicStorage`]
195    /// can be accessed by multiple processes concurrently therefore it must be constant or
196    /// thread-safe.
197    fn get(&self) -> &T;
198
199    /// The default suffix of every dynamic storage
200    fn default_suffix() -> FileName {
201        unsafe { FileName::new_unchecked(b".dyn") }
202    }
203
204    #[doc(hidden)]
205    /// # Safety
206    ///
207    /// * ensure that the contained type matches the semantic type_name given with `T`
208    /// * if `T` is some arbitary placeholder, then only use it to remove the concept or list it
209    ///   * DO NOT OPEN IT
210    unsafe fn __internal_set_type_name_in_config(config: &mut Self::Configuration, type_name: &str);
211}