Skip to main content

iceoryx2_cal/shared_memory/
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//! A [`SharedMemory`] is identified by a name and allows two processes to share memory with each
14//! other (inter-process memory).
15//!
16//! One process creates the [`SharedMemory`] and multiple processes can then open the
17//! [`SharedMemory`] with the [`SharedMemoryBuilder`].
18//!
19//! # Example
20//!
21//! ```
22//! use iceoryx2_bb_posix::access_mode::AccessMode;
23//! use iceoryx2_cal::shared_memory::*;
24//! use iceoryx2_cal::named_concept::*;
25//! use iceoryx2_cal::shm_allocator::pool_allocator::PoolAllocator;
26//! use iceoryx2_cal::shm_allocator::pool_allocator;
27//! use iceoryx2_bb_system_types::file_name::FileName;
28//! use iceoryx2_bb_container::semantic_string::SemanticString;
29//! use core::alloc::Layout;
30//!
31//! fn process_one<Shm: SharedMemory<PoolAllocator>>() {
32//!     let shm_name = FileName::new(b"myShmName").unwrap();
33//!     let allocator_config = pool_allocator::Config {
34//!         // we want to allocate [`u64`]
35//!         bucket_layout: Layout::new::<u64>()
36//!     };
37//!     let shm = Shm::Builder::new(&shm_name).size(1024).create(&allocator_config).unwrap();
38//!     let mut shm_pointer = shm.allocate(Layout::new::<u64>()).unwrap();
39//!     unsafe { shm_pointer.data_ptr.write(123) };
40//!
41//!     // send shm_pointer to another process with [`ZeroCopyConnection`]
42//! }
43//!
44//! fn process_two<Shm: SharedMemory<PoolAllocator>>() {
45//!     let shm_name = FileName::new(b"myShmName").unwrap();
46//!     let allocator_config = pool_allocator::Config {
47//!         // we want to allocate [`u64`]
48//!         bucket_layout: Layout::new::<u64>()
49//!     };
50//!     let shm = Shm::Builder::new(&shm_name).size(1024)
51//!             .open(AccessMode::ReadWrite).unwrap();
52//!     let mut shm_pointer = shm.allocate(Layout::new::<u64>()).unwrap();
53//!     unsafe { shm_pointer.data_ptr.write(31) }
54//!
55//!     // send shm_pointer to another process with [`ZeroCopyConnection`]
56//! }
57//! ```
58
59pub mod common;
60pub mod file;
61pub mod posix;
62pub mod process_local;
63pub mod recommended;
64
65use core::{fmt::Debug, time::Duration};
66
67pub use crate::shm_allocator::*;
68use crate::static_storage::file::{NamedConcept, NamedConceptBuilder, NamedConceptMgmt};
69use iceoryx2_bb_elementary_traits::testing::abandonable::Abandonable;
70use iceoryx2_bb_posix::file::AccessMode;
71use iceoryx2_bb_system_types::file_name::*;
72use pool_allocator::PoolAllocator;
73
74/// Failure returned by [`SharedMemoryBuilder::create()`]
75#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
76pub enum SharedMemoryCreateError {
77    AlreadyExists,
78    SizeIsZero,
79    InsufficientPermissions,
80    InternalError,
81}
82
83impl core::fmt::Display for SharedMemoryCreateError {
84    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
85        write!(f, "SharedMemoryCreateError::{self:?}")
86    }
87}
88
89impl core::error::Error for SharedMemoryCreateError {}
90
91/// Failure returned by [`SharedMemoryBuilder::open()`]
92#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
93pub enum SharedMemoryOpenError {
94    DoesNotExist,
95    InsufficientPermissions,
96    SizeIsZero,
97    SizeDoesNotFit,
98    WrongAllocatorSelected,
99    InitializationNotYetFinalized,
100    VersionMismatch,
101    InternalError,
102}
103
104impl core::fmt::Display for SharedMemoryOpenError {
105    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
106        write!(f, "SharedMemoryOpenError::{self:?}")
107    }
108}
109
110impl core::error::Error for SharedMemoryOpenError {}
111
112/// Represents a pointer pointing to some [`SharedMemory`]. Consists of the actual data pointer and
113/// an [`PointerOffset`] which can be used in combination with a
114/// [`crate::zero_copy_connection::ZeroCopyConnection`]
115#[derive(Debug)]
116pub struct ShmPointer {
117    pub offset: PointerOffset,
118    pub data_ptr: *mut u8,
119}
120
121#[doc(hidden)]
122pub(crate) mod details {
123    use super::*;
124
125    pub trait SharedMemoryLowLevelAPI<Allocator: ShmAllocator> {
126        fn allocator(&self) -> &Allocator;
127    }
128}
129
130/// Creates [`SharedMemory`].
131pub trait SharedMemoryBuilder<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>:
132    NamedConceptBuilder<Shm>
133{
134    /// Defines if a newly created [`SharedMemory`] owns the underlying resources
135    fn has_ownership(self, value: bool) -> Self;
136
137    /// Sets the size of the [`SharedMemory`]. Only relevant when the [`SharedMemory`] is created
138    /// otherwise the already initialized [`SharedMemory`] is completely mapped into the process
139    /// space.
140    fn size(self, value: usize) -> Self;
141
142    /// The timeout defines how long the [`SharedMemoryBuilder`] should wait for
143    /// [`SharedMemoryBuilder::create()`] to finialize
144    /// the initialization. This is required when the [`SharedMemory`] is created and initialized
145    /// concurrently from another process. By default it is set to [`Duration::ZERO`] for no
146    /// timeout.
147    fn timeout(self, value: Duration) -> Self;
148
149    /// Creates new [`SharedMemory`]. If it already exists the method will fail.
150    fn create(
151        self,
152        allocator_config: &Allocator::Configuration,
153    ) -> Result<Shm, SharedMemoryCreateError>;
154
155    /// Opens already existing [`SharedMemory`]. If it does not exist or the initialization is not
156    /// yet finished the method will fail.
157    fn open(self, access_mode: AccessMode) -> Result<Shm, SharedMemoryOpenError>;
158}
159
160/// Abstract concept of a memory shared between multiple processes. Can be created with the
161/// [`SharedMemoryBuilder`].
162pub trait SharedMemory<Allocator: ShmAllocator>:
163    Sized
164    + Debug
165    + NamedConcept
166    + NamedConceptMgmt
167    + details::SharedMemoryLowLevelAPI<Allocator>
168    + Send
169    + Abandonable
170{
171    type Builder: SharedMemoryBuilder<Allocator, Self>;
172
173    /// Returns the size of the shared memory.
174    fn size(&self) -> usize;
175
176    /// Returns the max supported alignment.
177    fn max_alignment(&self) -> usize;
178
179    /// Returns the start address of the shared memory. Used by the [`ShmPointer`] to calculate
180    /// the actual memory position.
181    fn payload_start_address(&self) -> usize;
182
183    /// Allocates memory. The alignment in the layout must be smaller or equal
184    /// [`SharedMemory::max_alignment()`] otherwise the method will fail.
185    fn allocate(&self, layout: core::alloc::Layout) -> Result<ShmPointer, ShmAllocationError>;
186
187    /// Release previously allocated memory
188    ///
189    /// # Safety
190    ///
191    ///  * the offset must be acquired with [`SharedMemory::allocate()`] - extracted from the
192    ///    [`ShmPointer`]
193    ///  * the layout must be identical to the one used in [`SharedMemory::allocate()`]
194    unsafe fn deallocate(&self, offset: PointerOffset, layout: core::alloc::Layout);
195
196    /// Returns if the [`SharedMemory`] supports persistency, meaning that the underlying OS
197    /// resource remain even when every [`SharedMemory`] instance in every process was removed.
198    fn does_support_persistency() -> bool;
199
200    /// Returns true if the [`SharedMemory`] holds the ownership, otherwise false
201    fn has_ownership(&self) -> bool;
202
203    /// Acquires the ownership of the [`SharedMemory`]. When the object goes out of scope the
204    /// underlying resources will be removed.
205    fn acquire_ownership(&self);
206
207    /// Releases the ownership of the [`SharedMemory`] meaning when it goes out of scope the
208    /// underlying resource will not be removed.
209    fn release_ownership(&self);
210
211    /// The default suffix of every shared memory
212    fn default_suffix() -> FileName {
213        unsafe { FileName::new_unchecked(b".shm") }
214    }
215}
216
217pub trait SharedMemoryForPoolAllocator: SharedMemory<PoolAllocator> {
218    /// Release previously allocated memory
219    ///
220    /// # Safety
221    ///
222    ///  * the offset must be acquired with [`SharedMemory::allocate()`] - extracted from the
223    ///    [`ShmPointer`]
224    unsafe fn deallocate_bucket(&self, offset: PointerOffset);
225
226    /// Returns the bucket size of the [`PoolAllocator`]
227    fn bucket_size(&self) -> usize;
228}