Cheetah Software  1.0
SharedMemory.h
Go to the documentation of this file.
1 
7 #ifndef PROJECT_SHAREDMEMORY_H
8 #define PROJECT_SHAREDMEMORY_H
9 
10 #include <fcntl.h> /* For O_* constants */
11 #include <semaphore.h>
12 #include <sys/mman.h>
13 #include <sys/stat.h> /* For mode constants */
14 #include <unistd.h>
15 #include <cassert>
16 #include <cstring>
17 #include <stdexcept>
18 #include <string>
19 #include "cTypes.h"
20 
21 #define DEVELOPMENT_SIMULATOR_SHARED_MEMORY_NAME "development-simulator"
22 
28  public:
39  void init(unsigned int value) {
40  if (!_init) {
41  if (sem_init(&_sem, 1, value)) {
42  printf("[ERROR] Failed to initialize shared memory semaphore: %s\n",
43  strerror(errno));
44  } else {
45  _init = true;
46  }
47  }
48  }
49 
53  void increment() { sem_post(&_sem); }
54 
59  void decrement() { sem_wait(&_sem); }
60 
66  bool tryDecrement() { return (sem_trywait(&_sem)) == 0; }
67 
72  bool decrementTimeout(u64 seconds, u64 nanoseconds) {
73  struct timespec ts;
74  clock_gettime(CLOCK_REALTIME, &ts);
75  ts.tv_nsec += nanoseconds;
76  ts.tv_sec += seconds;
77  ts.tv_sec += ts.tv_nsec / 1000000000;
78  ts.tv_nsec %= 1000000000;
79  return (sem_timedwait(&_sem, &ts) == 0);
80  }
81 
86  void destroy() { sem_destroy(&_sem); }
87 
88  private:
89  sem_t _sem;
90  bool _init = false;
91 };
92 
111 template <typename T>
113  public:
114  SharedMemoryObject() = default;
115 
125  bool createNew(const std::string& name, bool allowOverwrite = false) {
126  bool hadToDelete = false;
127  assert(!_data);
128  _name = name;
129  _size = sizeof(T);
130  printf("[Shared Memory] open new %s, size %ld bytes\n", name.c_str(),
131  _size);
132 
133  _fd = shm_open(name.c_str(), O_RDWR | O_CREAT,
134  S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
135  if (_fd == -1) {
136  printf("[ERROR] SharedMemoryObject shm_open failed: %s\n",
137  strerror(errno));
138  throw std::runtime_error("Failed to create shared memory!");
139  return false;
140  }
141 
142  struct stat s;
143  if (fstat(_fd, &s)) {
144  printf("[ERROR] SharedMemoryObject::createNew(%s) stat: %s\n",
145  name.c_str(), strerror(errno));
146  throw std::runtime_error("Failed to create shared memory!");
147  return false;
148  }
149 
150  if (s.st_size) {
151  printf(
152  "[Shared Memory] SharedMemoryObject::createNew(%s) on something that "
153  "wasn't new (size is %ld bytes)\n",
154  _name.c_str(), s.st_size);
155  hadToDelete = true;
156  if (!allowOverwrite)
157  throw std::runtime_error(
158  "Failed to create shared memory - it already exists.");
159  printf("\tusing existing shared memory!\n");
160  // return false;
161  }
162 
163  if (ftruncate(_fd, _size)) {
164  printf("[ERROR] SharedMemoryObject::createNew(%s) ftruncate(%ld): %s\n",
165  name.c_str(), _size, strerror(errno));
166  throw std::runtime_error("Failed to create shared memory!");
167  return false;
168  }
169 
170  void* mem =
171  mmap(nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0);
172  if (mem == MAP_FAILED) {
173  printf("[ERROR] SharedMemory::createNew(%s) mmap fail: %s\n",
174  _name.c_str(), strerror(errno));
175  throw std::runtime_error("Failed to create shared memory!");
176  return false;
177  }
178 
179  // there is a chance that the shared memory is not zeroed if we are reusing
180  // old memory. this causes all sorts of weird issues, especially if the
181  // layout of the object in memory has changed.
182  memset(mem, 0, _size);
183 
184  _data = (T*)mem;
185  return hadToDelete;
186  }
187 
191  void attach(const std::string& name) {
192  assert(!_data);
193  _name = name;
194  _size = sizeof(T);
195  printf("[Shared Memory] open existing %s size %ld bytes\n", name.c_str(),
196  _size);
197  _fd = shm_open(name.c_str(), O_RDWR,
198  S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
199  if (_fd == -1) {
200  printf("[ERROR] SharedMemoryObject::attach shm_open(%s) failed: %s\n",
201  _name.c_str(), strerror(errno));
202  throw std::runtime_error("Failed to create shared memory!");
203  return;
204  }
205 
206  struct stat s;
207  if (fstat(_fd, &s)) {
208  printf("[ERROR] SharedMemoryObject::attach(%s) stat: %s\n", name.c_str(),
209  strerror(errno));
210  throw std::runtime_error("Failed to create shared memory!");
211  return;
212  }
213 
214  if ((size_t)s.st_size != _size) {
215  printf(
216  "[ERROR] SharedMemoryObject::attach(%s) on something that was "
217  "incorrectly "
218  "sized (size is %ld bytes, should be %ld)\n",
219  _name.c_str(), s.st_size, _size);
220  throw std::runtime_error("Failed to create shared memory!");
221  return;
222  }
223 
224  void* mem =
225  mmap(nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0);
226  if (mem == MAP_FAILED) {
227  printf("[ERROR] SharedMemory::attach(%s) mmap fail: %s\n", _name.c_str(),
228  strerror(errno));
229  throw std::runtime_error("Failed to create shared memory!");
230  return;
231  }
232 
233  _data = (T*)mem;
234  }
235 
241  void closeNew() {
242  assert(_data);
243  // first, unmap
244  if (munmap((void*)_data, _size)) {
245  printf("[ERROR] SharedMemoryObject::closeNew (%s) munmap %s\n",
246  _name.c_str(), strerror(errno));
247  throw std::runtime_error("Failed to create shared memory!");
248  return;
249  }
250 
251  _data = nullptr;
252 
253  if (shm_unlink(_name.c_str())) {
254  printf("[ERROR] SharedMemoryObject::closeNew (%s) shm_unlink %s\n",
255  _name.c_str(), strerror(errno));
256  throw std::runtime_error("Failed to create shared memory!");
257  return;
258  }
259 
260  // close fd
261  if (close(_fd)) {
262  printf("[ERROR] SharedMemoryObject::closeNew (%s) close %s\n",
263  _name.c_str(), strerror(errno));
264  throw std::runtime_error("Failed to create shared memory!");
265  return;
266  }
267 
268  _fd = 0;
269  }
270 
277  void detach() {
278  assert(_data);
279  // first, unmap
280  if (munmap((void*)_data, _size)) {
281  printf("[ERROR] SharedMemoryObject::detach (%s) munmap %s\n",
282  _name.c_str(), strerror(errno));
283  throw std::runtime_error("Failed to create shared memory!");
284  return;
285  }
286 
287  _data = nullptr;
288 
289  // close fd
290  if (close(_fd)) {
291  printf("[ERROR] SharedMemoryObject::detach (%s) close %s\n",
292  _name.c_str(), strerror(errno));
293  throw std::runtime_error("Failed to create shared memory!");
294  return;
295  }
296 
297  _fd = 0;
298  }
299 
303  T* get() {
304  assert(_data);
305  return _data;
306  }
307 
311  T& operator()() {
312  assert(_data);
313  return *_data;
314  }
315 
316  private:
317  T* _data = nullptr;
318  std::string _name;
319  size_t _size;
320  int _fd;
321 };
322 
323 #endif // PROJECT_SHAREDMEMORY_H
Common types that are only valid in C++.
std::string _name
Definition: SharedMemory.h:318
void attach(const std::string &name)
Definition: SharedMemory.h:191
void init(unsigned int value)
Definition: SharedMemory.h:39
bool createNew(const std::string &name, bool allowOverwrite=false)
Definition: SharedMemory.h:125
uint64_t u64
Definition: cTypes.h:17
bool decrementTimeout(u64 seconds, u64 nanoseconds)
Definition: SharedMemory.h:72