CppCommon  1.0.4.1
C++ Common Library
shared_memory.cpp
Go to the documentation of this file.
1 
9 #include "system/shared_memory.h"
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 
25 namespace CppCommon {
26 
28 
29 class SharedMemory::Impl
30 {
31 public:
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 
160 private:
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 
187 SharedMemory::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 
204 void* SharedMemory::ptr() { return impl().ptr(); }
205 const void* SharedMemory::ptr() const { return impl().ptr(); }
206 bool 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.
Definition: shared_memory.h:50
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.
Definition: shared_memory.h:48
#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.
Definition: token_bucket.h:15
Shared memory manager definition.
Aligned storage validator definition.