Cbeam
Loading...
Searching...
No Matches
interprocess_shared_memory.hpp
Go to the documentation of this file.
1/*
2Copyright (c) 2025 acrion innovations GmbH
3Authors: Stefan Zipproth, s.zipproth@acrion.ch
4
5This file is part of Cbeam, see https://github.com/acrion/cbeam and https://cbeam.org
6
7Cbeam is offered under a commercial and under the AGPL license.
8For commercial licensing, contact us at https://acrion.ch/sales. For AGPL licensing, see below.
9
10AGPL licensing:
11
12Cbeam is free software: you can redistribute it and/or modify
13it under the terms of the GNU Affero General Public License as published by
14the Free Software Foundation, either version 3 of the License, or
15(at your option) any later version.
16
17Cbeam is distributed in the hope that it will be useful,
18but WITHOUT ANY WARRANTY; without even the implied warranty of
19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20GNU Affero General Public License for more details.
21
22You should have received a copy of the GNU Affero General Public License
23along with Cbeam. If not, see <https://www.gnu.org/licenses/>.
24*/
25
26#pragma once
27
29#include <cbeam/error/runtime_error.hpp> // for cbeam::error:runtime_error
30
31#ifdef _WIN32
33
35#else
36 #include <fcntl.h> // for O_CREAT, O_RDWR, S_IRUSR, S_IWUSR
37 #include <sys/mman.h> // for size_t, mmap, munmap, shm_open, shm_unlink, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE
38 #include <unistd.h> // for close, ftruncate
39#endif
40
41#include <cstddef> // for std::size_t
42
43#include <exception> // for std::exception
44#include <memory> // for std::allocator, std::unique_ptr, std::make_unique
45#include <mutex> // for std::lock_guard
46#include <string> // for std::operator+, std::string, std::basic_string, std::char_traits, std::string_literals
47
49{
61 {
62 public:
64 {
66
67 public:
69 : _mutex(mutex)
70 {
71 _mutex.lock();
72 }
73
74 ~lock_guard() noexcept
75 {
76 _mutex.unlock();
77 }
78
79 lock_guard(const lock_guard&) = default;
80 lock_guard& operator=(const lock_guard&) = delete;
81 };
82
88 interprocess_shared_memory(const std::string& unique_identifier, std::size_t size)
89#ifdef _WIN32
90 : _shared_memory_name{"Local\\s_" + unique_identifier}
91#else
92 : _shared_memory_name{"/s_" + unique_identifier}
93#endif
94 , _mutex{(std::string{"m_"} + unique_identifier).c_str()}
95 {
96 using namespace std::string_literals;
97
98 std::lock_guard<cbeam::concurrency::named_recursive_mutex> lock(_mutex);
99
100#ifdef _WIN32
101 _shared_memory = CreateFileMappingA(
102 INVALID_HANDLE_VALUE, // use paging file
103 NULL, // default security
104 PAGE_READWRITE, // read/write access
105 static_cast<DWORD>(0xFFFFFFFF & (size >> 32)), // maximum object size (high-order DWORD)
106 static_cast<DWORD>(0xFFFFFFFF & size), // maximum object size (low-order DWORD)
107 _shared_memory_name.c_str()); // name of mapping object
108
109 if (_shared_memory == NULL)
110 {
111 if (GetLastError() == ERROR_ALREADY_EXISTS)
112 {
113 _shared_memory = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, _shared_memory_name.c_str());
114 if (_shared_memory == NULL)
115 {
116 throw cbeam::error::runtime_error("cbeam::memory::interprocess_shared_memory: Failed to open existing shared memory for '" + unique_identifier + "': " + platform::get_last_windows_error_message());
117 }
118 }
119 else
120 {
121 throw cbeam::error::runtime_error("cbeam::memory::interprocess_shared_memory: Failed to create file mapping for '" + unique_identifier + "': " + platform::get_last_windows_error_message());
122 }
123 }
124
125 _region = MapViewOfFile(
126 _shared_memory, // handle to map object
127 FILE_MAP_ALL_ACCESS, // read/write permission
128 0,
129 0,
130 size);
131
132 if (_region == NULL)
133 {
134 CloseHandle(_shared_memory);
135 throw cbeam::error::runtime_error("cbeam::memory::interprocess_shared_memory: Failed to map view for '" + unique_identifier + "': " + platform::get_last_windows_error_message());
136 }
137
138 CBEAM_LOG_DEBUG("cbeam::memory::interprocess_shared_memory: Created or opened shared memory " + unique_identifier);
139#else
140 int shared_memory = shm_open(_shared_memory_name.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
141 if (shared_memory == -1)
142 {
143 throw cbeam::error::runtime_error("cbeam::memory::interprocess_shared_memory: Failed to create/open shared memory: " + unique_identifier);
144 }
145
146 if (ftruncate(shared_memory, size) == -1)
147 {
148 close(shared_memory);
149 throw cbeam::error::runtime_error("cbeam::memory::interprocess_shared_memory: Failed to set size of shared memory: " + unique_identifier);
150 }
151
152 void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, shared_memory, 0);
153 if (addr == MAP_FAILED)
154 {
155 close(shared_memory);
156 throw cbeam::error::runtime_error("cbeam::memory::interprocess_shared_memory: Failed to map shared memory: " + unique_identifier);
157 }
158
159 close(shared_memory);
160 _region = std::make_unique<posix_mapped_region>(addr, size);
161#endif
162 }
163
165 {
166 try
167 {
168 std::lock_guard<cbeam::concurrency::named_recursive_mutex> lock(_mutex);
169
170#ifdef _WIN32
171 UnmapViewOfFile(_region);
172 CloseHandle(_shared_memory);
173#else
174 _region.reset();
175 shm_unlink(_shared_memory_name.c_str());
176#endif
177 }
178 catch (const std::system_error& ex)
179 {
180 CBEAM_LOG(std::string{"cbeam::memory::interprocess_shared_memory::~interprocess_shared_memory: Could not lock the mutex. This indicates a serious (unexpected) bug that must be fixed during development phase: "} + ex.what());
181 assert(false);
182 }
183 }
184
189 void* data() const
190 {
191#ifdef _WIN32
192 return _region;
193#else
194 return _region->get_address();
195#endif
196 }
197
202 size_t capacity() const noexcept
203 {
204#ifdef _WIN32
205 MEMORY_BASIC_INFORMATION info;
206 VirtualQuery(_region, &info, sizeof(info));
207 return info.RegionSize;
208#else
209 return _region->get_size();
210#endif
211 }
212
218 {
219 return lock_guard(_mutex);
220 }
221
226
227 private:
228#ifdef _WIN32
229 HANDLE _shared_memory;
230 LPVOID _region;
231#else
232 class posix_mapped_region
233 {
234 public:
235 posix_mapped_region(void* addr, size_t size)
236 : _addr(addr)
237 , _size(size) {}
238
239 ~posix_mapped_region() noexcept
240 {
241 munmap(_addr, _size);
242 }
243
244 void* get_address() const noexcept { return _addr; }
245 size_t get_size() const noexcept { return _size; }
246
247 private:
248 void* _addr;
249 size_t _size;
250 };
251
252 std::unique_ptr<posix_mapped_region> _region;
253#endif
254 const std::string _shared_memory_name;
256 };
257}
Provides a cross-platform interface for recursive named mutexes, enabling interprocess synchronizatio...
Definition named_recursive_mutex.hpp:85
Definition interprocess_shared_memory.hpp:64
~lock_guard() noexcept
Definition interprocess_shared_memory.hpp:74
lock_guard & operator=(const lock_guard &)=delete
lock_guard(cbeam::concurrency::named_recursive_mutex &mutex)
Definition interprocess_shared_memory.hpp:68
lock_guard get_lock_guard() const
Acquires a lock_guard for mutex synchronization.
Definition interprocess_shared_memory.hpp:217
size_t capacity() const noexcept
Returns the size of the shared memory region.
Definition interprocess_shared_memory.hpp:202
interprocess_shared_memory & operator=(interprocess_shared_memory &&)=delete
void * data() const
Retrieves the starting address of the shared memory region.
Definition interprocess_shared_memory.hpp:189
interprocess_shared_memory(const interprocess_shared_memory &)=delete
interprocess_shared_memory(const std::string &unique_identifier, std::size_t size)
Constructor that initializes the shared memory segment.
Definition interprocess_shared_memory.hpp:88
interprocess_shared_memory & operator=(const interprocess_shared_memory &)=delete
virtual ~interprocess_shared_memory() noexcept
Definition interprocess_shared_memory.hpp:164
interprocess_shared_memory(interprocess_shared_memory &&)=delete
#define CBEAM_LOG(s)
Logs a message using cbeam::logging::log_manager.
Definition log_manager.hpp:124
#define CBEAM_LOG_DEBUG(s)
Logs a debug message if CBEAM_DEBUG_LOGGING is enabled.
Definition log_manager.hpp:138
Houses abstractions for shared-memory and interprocess data exchange. This includes interprocess_shar...
Definition interprocess_shared_memory.hpp:49
std::string get_last_windows_error_message()
Retrieves a descriptive error message for the last Windows API error.
Definition windows_config.hpp:66
Header file to manage inclusion of windows.h with specific settings.