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}