CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
shared_memory.cpp
Go to the documentation of this file.
1
10
11#include "errors/fatal.h"
13
14#include <cassert>
15#include <cstring>
16
17#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
18#include <sys/mman.h>
19#include <fcntl.h>
20#include <unistd.h>
21#elif defined(_WIN32) || defined(_WIN64)
22#include <windows.h>
23#endif
24
25namespace CppCommon {
26
28
29class SharedMemory::Impl
30{
31public:
32 Impl(const std::string& name, size_t size)
33 {
34 assert(!name.empty() && "Shared memory buffer name must not be empty!");
35 assert((size > 0) && "Shared memory buffer size must be greater than zero!");
36
37 size_t total = SHARED_MEMORY_HEADER_SIZE + size;
38#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
39 _name = "/" + name;
40 _owner = true;
41
42 // Try to create a shared memory handler
43 _shared = shm_open(_name.c_str(), (O_CREAT | O_EXCL | O_RDWR), (S_IRUSR | S_IWUSR));
44 if (_shared == -1)
45 {
46 // Try to open a shared memory handler
47 _shared = shm_open(_name.c_str(), (O_CREAT | O_RDWR), (S_IRUSR | S_IWUSR));
48 if (_shared == -1)
49 throwex SystemException("Failed to create or open a shared memory handler!");
50 else
51 _owner = false;
52 }
53 else
54 {
55 // Truncate a shared memory handler
56 int result = ftruncate(_shared, total);
57 if (result != 0)
58 throwex SystemException("Failed to truncate a shared memory handler!");
59 }
60
61 // Map a shared memory buffer
62 _ptr = mmap(nullptr, total, (PROT_READ | PROT_WRITE), MAP_SHARED, _shared, 0);
63 if (_ptr == MAP_FAILED)
64 {
65 close(_shared);
66 shm_unlink(_name.c_str());
67 throwex SystemException("Failed to map a shared memory buffer!");
68 }
69#elif defined(_WIN32) || defined(_WIN64)
70 _name = "Global\\" + name;
71 _owner = false;
72
73 // Try to open a shared memory handler
74 _shared = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, _name.c_str());
75 if (_shared == nullptr)
76 {
77 // Try to create a shared memory handler
78 _shared = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)total, _name.c_str());
79 if (_shared == nullptr)
80 throwex SystemException("Failed to create or open a shared memory handler!");
81 else
82 _owner = true;
83 }
84
85 // Map a shared memory buffer
86 _ptr = MapViewOfFile(_shared, FILE_MAP_ALL_ACCESS, 0, 0, total);
87 if (_ptr == nullptr)
88 {
89 CloseHandle(_shared);
90 throwex SystemException("Failed to map a shared memory buffer!");
91 }
92#endif
93 static const char* SHARED_MEMORY_HEADER_PREFIX = "SHMM";
94
95 // Owner must fill the shared memory header and user must check the shared memory header
96 if (_owner)
97 {
98 // Fill shared memory header
99 std::memcpy(((SharedMemoryHeader*)_ptr)->prefix, SHARED_MEMORY_HEADER_PREFIX, 4 );
100 ((SharedMemoryHeader*)_ptr)->size = size;
101 }
102 else
103 {
104 // Check shared memory header
105 bool is_valid_prefix = (std::strncmp(((SharedMemoryHeader*)_ptr)->prefix, SHARED_MEMORY_HEADER_PREFIX, 4) == 0);
106 bool is_valid_size = (((SharedMemoryHeader*)_ptr)->size == size);
107 if (!is_valid_prefix || !is_valid_size)
108 {
109#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
110 munmap(_ptr, total);
111 close(_shared);
112#elif defined(_WIN32) || defined(_WIN64)
113 UnmapViewOfFile(_ptr);
114 CloseHandle(_shared);
115#endif
116 if (!is_valid_prefix)
117 throwex SystemException("Invalid shared memory buffer prefix!");
118 if (!is_valid_size)
119 throwex SystemException("Invalid shared memory buffer size!");
120 }
121 }
122 }
123
124 ~Impl()
125 {
126#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
127 // Unmap the shared memory buffer
128 size_t total = ((SharedMemoryHeader*)_ptr)->size + SHARED_MEMORY_HEADER_SIZE;
129 int result = munmap(_ptr, total);
130 if (result != 0)
131 fatality(SystemException("Failed to unmap a shared memory buffer!"));
132
133 // Close the shared memory handler
134 result = close(_shared);
135 if (result != 0)
136 fatality(SystemException("Failed to close a shared memory handler!"));
137
138 // Unlink the shared memory handler (owner only)
139 if (_owner)
140 {
141 result = shm_unlink(_name.c_str());
142 if (result != 0)
143 fatality(SystemException("Failed to unlink a shared memory handler!"));
144 }
145#elif defined(_WIN32) || defined(_WIN64)
146 // Unmap the shared memory buffer
147 if (!UnmapViewOfFile(_ptr))
148 fatality(SystemException("Failed to unmap a shared memory buffer!"));
149
150 // Close the shared memory handler
151 if (!CloseHandle(_shared))
152 fatality(SystemException("Failed to close a shared memory handler!"));
153#endif
154 }
155
156 void* ptr() { return (uint8_t*)_ptr + SHARED_MEMORY_HEADER_SIZE; }
157 const void* ptr() const { return _ptr; }
158 bool owner() const { return _owner; }
159
160private:
161 // Shared memory header size
162 static const int SHARED_MEMORY_HEADER_SIZE = 64;
163
164 // Shared memory header structure
165 struct SharedMemoryHeader
166 {
167 // Prefix must always be "SHMM"
168 char prefix[4];
169 // Padding
170 char padding[4];
171 // Block size
172 size_t size;
173 };
174
175 std::string _name;
176#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
177 int _shared;
178#elif defined(_WIN32) || defined(_WIN64)
179 HANDLE _shared;
180#endif
181 void* _ptr;
182 bool _owner;
183};
184
186
187SharedMemory::SharedMemory(const std::string& name, size_t size) : _name(name), _size(size)
188{
189 // Check implementation storage parameters
190 [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
191 static_assert((StorageSize >= sizeof(Impl)), "SharedMemory::StorageSize must be increased!");
192 static_assert(((StorageAlign % alignof(Impl)) == 0), "SharedMemory::StorageAlign must be adjusted!");
193
194 // Create the implementation instance
195 new(&_storage)Impl(name, size);
196}
197
199{
200 // Delete the implementation instance
201 reinterpret_cast<Impl*>(&_storage)->~Impl();
202}
203
204void* SharedMemory::ptr() { return impl().ptr(); }
205const void* SharedMemory::ptr() const { return impl().ptr(); }
206bool SharedMemory::owner() const { return impl().owner(); }
207
208} // namespace CppCommon
void * ptr()
Get the shared memory block pointer.
bool owner() const
Get the shared memory owner flag (true if the new one was created, false if the existing one was open...
size_t size() const noexcept
Get the shared memory block size.
SharedMemory(const std::string &name, size_t size)
Create a new or open existing block of shared memory with a given name and size.
const std::string & name() const noexcept
Get the shared memory block name.
#define throwex
Throw extended exception macro.
Definition exceptions.h:23
Fatal abort execution definition.
#define fatality(...)
Fatal abort execution extended macro.
Definition fatal.h:22
C++ Common project definitions.
Shared memory manager definition.
Aligned storage validator definition.