SHM
Shared-memorybasedHandy-communicationManager
shm_service.hpp
Go to the documentation of this file.
1 
13 #ifndef __SHM_SERVICE_LIB_H__
14 #define __SHM_SERVICE_LIB_H__
15 
16 #include <string>
17 #include <thread>
18 #include "shm_base.hpp"
19 
20 namespace irlab
21 {
22 
23 namespace shm
24 {
25 
26 // ****************************************************************************
32 // ****************************************************************************
33 template <class Req, class Res>
35 {
36 public:
37  ServiceServer(std::string name, Res (*input_func)(Req request), PERM perm = DEFAULT_PERM);
38  ~ServiceServer();
39 
40 private:
41  void initializeExclusiveAccess();
42  void loop();
43  static void called_loop(ServiceServer& ref)
44  {
45  ref.loop();
46  }
47 
48  Res (*func)(Req request);
49  pthread_t thread;
50 
51  std::string shm_name;
52  PERM shm_perm;
53  SharedMemory *shared_memory;
54 
55  uint8_t *memory_ptr;
56 
57  pthread_mutex_t *request_mutex;
58  pthread_cond_t *request_condition;
59  uint64_t *request_timestamp_usec;
60  Req *request_ptr;
61  pthread_mutex_t *response_mutex;
62  pthread_cond_t *response_condition;
63  uint64_t *response_timestamp_usec;
64  Res *response_ptr;
65 
66  uint64_t current_request_timestamp_usec;
67 };
68 
69 // ****************************************************************************
74 // ****************************************************************************
75 template <class Req, class Res>
77 {
78 public:
79  ServiceClient(std::string name);
80  ~ServiceClient();
81 
82  bool call(Req request, Res *response);
83 
84 private:
85  std::string shm_name;
86  SharedMemory *shared_memory;
87 
88  uint8_t *memory_ptr;
89 
90  pthread_mutex_t *request_mutex;
91  pthread_cond_t *request_condition;
92  uint64_t *request_timestamp_usec;
93  Req *request_ptr;
94  pthread_mutex_t *response_mutex;
95  pthread_cond_t *response_condition;
96  uint64_t *response_timestamp_usec;
97  Res *response_ptr;
98 
99  uint64_t current_response_timestamp_usec;
100 };
101 
102 // ****************************************************************************
103 // 関数定義
104 // (テンプレートクラス内の関数の定義はコンパイル時に実体化するのでヘッダに書く)
105 // ****************************************************************************
106 template <class Req, class Res>
107 ServiceServer<Req, Res>::ServiceServer(std::string name, Res (*input_func)(Req request), PERM perm)
108 : func(input_func)
109 , shm_name(name)
110 , shm_perm(perm)
111 , shared_memory(nullptr)
112 , memory_ptr(nullptr)
113 {
114  if (!std::is_standard_layout<Req>::value || !std::is_standard_layout<Res>::value)
115  {
116  throw std::runtime_error("shm::ServiceServer: Be setted not POD class!");
117  }
118 
119  shared_memory = new SharedMemoryPosix(shm_name, O_RDWR|O_CREAT, shm_perm);
120  shared_memory->connect( (sizeof(pthread_mutex_t)+sizeof(pthread_cond_t)+sizeof(uint64_t)) * 2 + sizeof(Req) + sizeof(Res));
121  if (shared_memory->isDisconnected())
122  {
123  throw std::runtime_error("shm::Publisher: Cannot get memory!");
124  }
125 
126  uint8_t *data_ptr = shared_memory->getPtr();
127  memory_ptr = data_ptr;
128  request_mutex = reinterpret_cast<pthread_mutex_t *>(data_ptr);
129  data_ptr += sizeof(pthread_mutex_t);
130  request_condition = reinterpret_cast<pthread_cond_t *>(data_ptr);
131  data_ptr += sizeof(pthread_cond_t);
132  request_timestamp_usec = reinterpret_cast<uint64_t *>(data_ptr);
133  data_ptr += sizeof(uint64_t);
134  request_ptr = reinterpret_cast<Req *>(data_ptr);
135  data_ptr += sizeof(Req);
136  response_mutex = reinterpret_cast<pthread_mutex_t *>(data_ptr);
137  data_ptr += sizeof(pthread_mutex_t);
138  response_condition = reinterpret_cast<pthread_cond_t *>(data_ptr);
139  data_ptr += sizeof(pthread_cond_t);
140  response_timestamp_usec = reinterpret_cast<uint64_t *>(data_ptr);
141  data_ptr += sizeof(uint64_t);
142  response_ptr = reinterpret_cast<Res *>(data_ptr);
143 
144  initializeExclusiveAccess();
145 
146  struct timespec ts;
147  clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
148  *request_timestamp_usec = ((uint64_t) ts.tv_sec * 1000000L) + ((uint64_t) ts.tv_nsec / 1000L);
149  *response_timestamp_usec = *request_timestamp_usec;
150  current_request_timestamp_usec = *request_timestamp_usec;
151 
152  pthread_create(&thread, NULL, reinterpret_cast<void* (*)(void*)>(&ServiceServer<Req, Res>::called_loop), this);
153 }
154 
155 template <class Req, class Res>
156 ServiceServer<Req, Res>::~ServiceServer()
157 {
158  pthread_cancel(thread);
159 
160  shared_memory->disconnect();
161  if (shared_memory != nullptr)
162  {
163  delete shared_memory;
164  }
165 }
166 
167 template <class Req, class Res>
168 void
169 ServiceServer<Req, Res>::initializeExclusiveAccess()
170 {
171  pthread_condattr_t request_cond_attr;
172  pthread_condattr_init(&request_cond_attr);
173  pthread_condattr_setpshared(&request_cond_attr, PTHREAD_PROCESS_SHARED);
174  pthread_cond_init(request_condition, &request_cond_attr);
175  pthread_condattr_destroy(&request_cond_attr);
176 
177  pthread_mutexattr_t request_m_attr;
178  pthread_mutexattr_init(&request_m_attr);
179  pthread_mutexattr_setpshared(&request_m_attr, PTHREAD_PROCESS_SHARED);
180  pthread_mutex_init(request_mutex, &request_m_attr);
181  pthread_mutexattr_destroy(&request_m_attr);
182 
183  pthread_condattr_t response_cond_attr;
184  pthread_condattr_init(&response_cond_attr);
185  pthread_condattr_setpshared(&response_cond_attr, PTHREAD_PROCESS_SHARED);
186  pthread_cond_init(response_condition, &response_cond_attr);
187  pthread_condattr_destroy(&response_cond_attr);
188 
189  pthread_mutexattr_t response_m_attr;
190  pthread_mutexattr_init(&response_m_attr);
191  pthread_mutexattr_setpshared(&response_m_attr, PTHREAD_PROCESS_SHARED);
192  pthread_mutex_init(response_mutex, &response_m_attr);
193  pthread_mutexattr_destroy(&response_m_attr);
194 }
195 
196 template <class Req, class Res>
197 void
198 ServiceServer<Req, Res>::loop()
199 {
200  while (1)
201  {
202  while (current_request_timestamp_usec >= *request_timestamp_usec)
203  {
204  // Wait on the condvar
205  pthread_mutex_lock(request_mutex);
206  pthread_cond_wait(request_condition, request_mutex);
207  pthread_mutex_unlock(request_mutex);
208  }
209  current_request_timestamp_usec = *request_timestamp_usec;
210 
211  *response_ptr = func(*request_ptr);
212  struct timespec ts;
213  clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
214  *response_timestamp_usec = ((uint64_t) ts.tv_sec * 1000000L) + ((uint64_t) ts.tv_nsec / 1000L);
215 
216  pthread_cond_broadcast(response_condition);
217  }
218 }
219 
220 
221 template <class Req, class Res>
222 ServiceClient<Req, Res>::ServiceClient(std::string name)
223 : shm_name(name)
224 , shared_memory(nullptr)
225 {
226  if (!std::is_standard_layout<Req>::value || !std::is_standard_layout<Res>::value)
227  {
228  throw std::runtime_error("shm::ServiceClient: Be setted not POD class!");
229  }
230  shared_memory = new SharedMemoryPosix(shm_name, O_RDWR, static_cast<PERM>(0));
231 
232  struct timespec ts;
233  clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
234  current_response_timestamp_usec = ((uint64_t) ts.tv_sec * 1000000L) + ((uint64_t) ts.tv_nsec / 1000L);
235 }
236 
237 template <class Req, class Res>
238 ServiceClient<Req, Res>::~ServiceClient()
239 {
240  if (shared_memory != nullptr)
241  {
242  delete shared_memory;
243  }
244 }
245 
246 template <class Req, class Res>
247 bool
248 ServiceClient<Req, Res>::call(Req request, Res *response)
249 {
250  // Check the service shared memory existance.
251  if (shared_memory->isDisconnected())
252  {
253  shared_memory->connect();
254  if (shared_memory->isDisconnected())
255  {
256  return false;
257  }
258  uint8_t *data_ptr = shared_memory->getPtr();
259  memory_ptr = data_ptr;
260  request_mutex = reinterpret_cast<pthread_mutex_t *>(data_ptr);
261  data_ptr += sizeof(pthread_mutex_t);
262  request_condition = reinterpret_cast<pthread_cond_t *>(data_ptr);
263  data_ptr += sizeof(pthread_cond_t);
264  request_timestamp_usec = reinterpret_cast<uint64_t *>(data_ptr);
265  data_ptr += sizeof(uint64_t);
266  request_ptr = reinterpret_cast<Req *>(data_ptr);
267  data_ptr += sizeof(Req);
268  response_mutex = reinterpret_cast<pthread_mutex_t *>(data_ptr);
269  data_ptr += sizeof(pthread_mutex_t);
270  response_condition = reinterpret_cast<pthread_cond_t *>(data_ptr);
271  data_ptr += sizeof(pthread_cond_t);
272  response_timestamp_usec = reinterpret_cast<uint64_t *>(data_ptr);
273  data_ptr += sizeof(uint64_t);
274  response_ptr = reinterpret_cast<Res *>(data_ptr);
275  }
276 
277  // Set request to shared memory
278  *request_ptr = request;
279  struct timespec ts;
280  clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
281  *request_timestamp_usec = ((uint64_t) ts.tv_sec * 1000000L) + ((uint64_t) ts.tv_nsec / 1000L);
282 
283  pthread_cond_broadcast(request_condition);
284 
285  while (current_response_timestamp_usec >= *response_timestamp_usec)
286  {
287  // Wait on the condvar
288  pthread_mutex_lock(response_mutex);
289  pthread_cond_wait(response_condition, response_mutex);
290  pthread_mutex_unlock(response_mutex);
291  }
292  current_response_timestamp_usec = *response_timestamp_usec;
293 
294  // Get response from shared memory
295  *response = *response_ptr;
296 
297  return true;
298 }
299 
300 }
301 
302 }
303 
304 #endif //__SHM_SERVICE_LIB_H__
shm_base.hpp
Basic class definitions for accessing shared memory, ring buffers, etc. The notation is complianted R...
irlab::shm::PERM
PERM
Definition: shm_base.hpp:40
irlab::shm::SharedMemory
Class that abstracts the method of accessing shared memory.
Definition: shm_base.hpp:84
irlab::shm::ServiceClient
共有メモリからトピックを取得する購読者を表現するクラス
Definition: shm_service.hpp:76
irlab::shm::ServiceServer
共有メモリで受信したリクエストからレスポンスを返すサーバーを表現するクラス
Definition: shm_service.hpp:34