Galaxis Codebase  1.0.0
Team Galaxis software stack for the Carolo Cup 2023 - ROS2 based software
SharedMemory.cpp
Go to the documentation of this file.
1 #include "com/SharedMemory.hpp"
2 
3 #include <errno.h>
4 #include <thread>
5 #include <iostream>
6 
7 // shared memory
8 #include <sys/mman.h>
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <chrono>
12 #include <cstring>
13 
14 #include <cassert>
15 
16 using namespace com;
17 using namespace std::chrono_literals;
18 
19 #define PERMISSION (0600)
20 
21 SharedMemory::SharedMemory(std::string name) {
22  assert(name.length() > 4);
23  if(name.at(0) != '/') {
24  name = "/" + name;
25  }
26  m_shmName = name;
27  m_semaphoreName = name;
28 };
29 
31  this->deallocate();
32 };
33 
34 bool SharedMemory::allocate(size_t sizeBytes) {
35  sizeBytes += 2 * sizeof(SharedData::tv_sec); // timestamps
36 
37  if(m_shmAddress != -1) {
38  std::clog << "[SharedMemory::allocate] Already allocated.\n";
39  return false;
40  }
41 
42  m_shmAddress = shm_open(m_shmName.c_str(), O_RDWR | O_CREAT | O_TRUNC, PERMISSION); // maybe switch to 0600
43  if (m_shmAddress == -1) {
44  std::cerr << "[SharedMemory::allocate] Failed to allocate shared memory.\n";
45  return false;
46  }
47  else {
48  std::clog << "[SharedMemory::allocate] Successfully allocated memory\n";
49  }
50 
51  int status = ftruncate(m_shmAddress, sizeBytes);
52  if(status != 0) {
53  std::cerr << "[SharedMemory::allocate] Failed to truncate shared memory. (Not enough space?)\n";
54  this->deallocate();
55  return false;
56  }
57  else {
58  m_shmSize = sizeBytes;
59  }
60 
61 
62  // map shared_memory to process space
63  m_sharedArea = mmap(NULL, m_shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_shmAddress, 0);
64  if(m_sharedArea == MAP_FAILED) {
65  std::cerr << "[SharedMemory::allocate] Failed to create semaphore. (Maybe already existing)\n";
66  this->deallocate();
67  return false;
68  }
69 
70 
71  // create semaphore
72  m_semaphore = sem_open(m_semaphoreName.c_str(), O_CREAT | O_EXCL, PERMISSION, 1); // 1 for 1 writer/reader
73  if(m_semaphore == SEM_FAILED) {
74  std::cerr << "[SharedMemory::allocate] Failed to create semaphore. (Maybe already existing)\n";
75  this->deallocate();
76  return false;
77  }
78 
79  // write timestamp 0,0 to shm
80  SharedData data;
81  data.dataSize = 0;
82  data.tv_sec = 0;
83  data.tv_nsec = 0;
84  this->write_mutexed(data);
85 
86  return true;
87 }
88 
90  bool status = true;
91  if(m_sharedArea != MAP_FAILED && m_sharedArea != nullptr) {
92  if (munmap(m_sharedArea, m_shmSize) == -1) {
93  std::cerr << "[SharedMemory::deallocate] Failed to unmap shared area\n";
94  status = false;
95  }
96  else {
97  std::clog << "[SharedMemory::deallocate] Unmapped shared area successfully\n";
98  }
99  }
100  if(m_semaphore != SEM_FAILED && m_semaphore != nullptr) {
101  if(sem_unlink(m_semaphoreName.c_str()) != 0) {
102  std::cerr << "[SharedMemory::deallocate] FAILED to unlink semaphore\n";
103  status = false;
104  }
105  else {
106  std::clog << "[SharedMemory::deallocate] Semaphore unlinked successfully\n";
107  m_semaphore = NULL;
108  }
109  }
110  if(m_shmAddress != -1 && m_shmSize != -1 && shm_unlink(m_shmName.c_str()) != 0) {
111  std::cerr << "[SharedMemory::deallocate] FAILED to deallocate shared memory\n";
112  status = false;
113  }
114  else {
115  std::clog << "[SharedMemory::deallocate] Deallocated shared memory successfully\n";
116  m_shmAddress = -1;
117  m_shmSize = -1;
118  }
119  return status;
120 }
121 
123  return m_shmSize - 2 * sizeof(SharedData::tv_sec);
124 }
125 
127  if(m_sharedArea == nullptr || m_sharedArea == MAP_FAILED) {
128  std::cerr << "[SharedMemory::write_mutexed] Shared memory not initialized/allocated! \n";
129  return false;
130  }
131 
132  size_t size = data.dataSize;
133  if(size > m_shmSize) {
134  std::cerr << "[SharedMemory::write_mutexed] Data too large to write into mutex. (Data is shrinked!)\n";
135  size = m_shmSize;
136  }
137  else if(size != m_shmSize - 8 && size != 0) {
138  std::clog << "[SharedMemory::write_mutexed] INFO: Data not as large as shared memory.\n";
139  }
140 
141  if(acquire_semaphore(true) == false) {
142  std::cerr << "[SharedMemory::write_mutexed] Could NOT acquire_semaphore. Skip writing to shared mem.\n";
143  return false;
144  }
145 
146  // write here mutexed
147  std::memcpy(m_sharedArea, &data.tv_sec, sizeof(data.tv_sec));
148  std::memcpy(m_sharedArea + sizeof(data.tv_sec), &data.tv_nsec, sizeof(data.tv_nsec));
149  std::memcpy(m_sharedArea + sizeof(data.tv_sec) + sizeof(data.tv_nsec), data.data, size);
150 
151  if(release_semaphore() == false) {
152  std::cerr << "[SharedMemory::write_mutexed] Semaphore NOT released.\n";
153  return false;
154  }
155 
156  return true;
157 }
158 
160  if(m_sharedArea == nullptr || m_sharedArea == MAP_FAILED) {
161  std::cerr << "[SharedMemory::is_new_data_available] Shared memory not initialized/allocated! \n";
162  return false;
163  }
164 
165  if(acquire_semaphore(true) == false) {
166  return false;
167  }
168 
169  uint32_t sec;
170  uint32_t nsec;
171 
172  // read here only timestamp
173  std::memcpy(&sec, m_sharedArea, sizeof(sec));
174  std::memcpy(&nsec, m_sharedArea + sizeof(sec), sizeof(nsec));
175 
176  if(release_semaphore() == false) {
177  std::cerr << "[SharedMemory::is_new_data_available] Semaphore NOT released.\n";
178  }
179 
180  return (sec != m_lastDataSec || nsec != m_lastDataNSec);
181 }
182 
183 size_t SharedMemory::read_mutexed(com::SharedData& data, size_t sizeToRead) {
184  if(m_sharedArea == nullptr || m_sharedArea == MAP_FAILED) {
185  std::cerr << "[SharedMemory::read_mutexed] Shared memory not initialized/allocated! \n";
186  return 0;
187  }
188 
189  if(acquire_semaphore(false) == false) {
190  return 0;
191  }
192 
193  // if larger than shared area
194  if(sizeToRead > m_shmSize - 2 * sizeof(data.tv_sec)) {
195  std::clog << "[SharedMemory::read_mutexed] Shared Memory not as large as desired size to read.\n";
196  sizeToRead = m_shmSize - 2 * sizeof(data.tv_sec);
197  }
198 
199  // read here mutexed
200  std::memcpy(&data.tv_sec, m_sharedArea, sizeof(data.tv_sec));
201  std::memcpy(&data.tv_nsec, m_sharedArea + sizeof(data.tv_sec), sizeof(data.tv_nsec));
202  std::memcpy(data.data, m_sharedArea + sizeof(data.tv_sec) + sizeof(data.tv_nsec), sizeToRead);
203 
204  if(release_semaphore() == false) {
205  std::cerr << "[SharedMemory::read_mutexed] Semaphore NOT released.\n";
206  }
207 
208  m_lastDataSec = data.tv_sec;
209  m_lastDataNSec = data.tv_nsec;
210 
211  return true;
212 }
213 
214 bool SharedMemory::acquire_semaphore(bool timedWait) {
215  struct timespec tms;
216  if (timedWait && clock_gettime(CLOCK_REALTIME,&tms) == 0) {
217  tms.tv_nsec += 10000000; // max 10ms
218  if(sem_timedwait(m_semaphore, &tms) != 0) {
219  std::cerr << "[SharedMemory::acquire_semaphore] FAILED to get semaphore (timed).\n";
220  return false;
221  }
222  }
223  else {
224  if(timedWait) std::clog << "[SharedMemory::acquire_semaphore] get clock not worked\n";
225  if(sem_wait(m_semaphore) != 0) {
226  std::cerr << "[SharedMemory::acquire_semaphore] FAILED to get semaphore.\n";
227  return false;
228  }
229  }
230 
231  return true;
232 }
233 
235  int maxTries = 10;
236  while(maxTries > 0 && sem_post(m_semaphore) != 0) {
237  std::cerr << "[SharedMemory::release_semaphore] FAILED to post semaphore! Retrying\n";
238  std::this_thread::sleep_for(10ms);
239  maxTries--;
240  }
241  return (maxTries > 0);
242 }
com::SharedMemory::acquire_semaphore
bool acquire_semaphore(bool timedWait=false)
Definition: SharedMemory.cpp:214
com::SharedData::data
uint8_t * data
Definition: SharedMemory.hpp:20
SharedMemory.hpp
com::SharedMemory::~SharedMemory
~SharedMemory()
Definition: SharedMemory.cpp:30
com::SharedData::dataSize
size_t dataSize
Definition: SharedMemory.hpp:21
com::SharedMemory::SharedMemory
SharedMemory()=delete
com::SharedMemory::write_mutexed
bool write_mutexed(com::SharedData const &data)
Definition: SharedMemory.cpp:126
com::SharedMemory::get_data_size
size_t get_data_size()
Definition: SharedMemory.cpp:122
com::SharedData::tv_sec
int32_t tv_sec
Definition: SharedMemory.hpp:18
com::SharedData::tv_nsec
uint32_t tv_nsec
Definition: SharedMemory.hpp:19
com::SharedMemory::is_new_data_available
bool is_new_data_available()
Definition: SharedMemory.cpp:159
com::SharedMemory::allocate
bool allocate(size_t sizeBytes)
Definition: SharedMemory.cpp:34
com::SharedData
Definition: SharedMemory.hpp:17
com::SharedMemory::deallocate
bool deallocate()
Definition: SharedMemory.cpp:89
com::SharedMemory::read_mutexed
size_t read_mutexed(com::SharedData &data, size_t sizeToRead)
Definition: SharedMemory.cpp:183
com::SharedMemory::release_semaphore
bool release_semaphore()
Definition: SharedMemory.cpp:234
com
Definition: SharedMemory.hpp:15
PERMISSION
#define PERMISSION
Definition: SharedMemory.cpp:19