13 #ifndef __SHM_ACTION_LIB_H__
14 #define __SHM_ACTION_LIB_H__
26 enum ACTION_STATUS : uint8_t
47 template <
class Goal,
class Result,
class Feedback>
54 void waitNewGoalAvailable();
58 bool isPreemptRequested();
61 void publishResult(
const Result& result);
62 void publishFeedback(
const Feedback& feedback);
65 void initializeExclusiveAccess();
73 uint64_t start_timestamp_us;
77 pthread_mutex_t *goal_mutex;
78 pthread_cond_t *goal_condition;
79 uint64_t *goal_timestamp_us;
81 pthread_mutex_t *result_mutex;
82 pthread_cond_t *result_condition;
83 uint64_t *result_timestamp_us;
85 Feedback *feedback_ptr;
86 ACTION_STATUS *status_ptr;
87 uint64_t *cancel_timestamp_us;
89 uint64_t current_goal_timestamp_usec;
98 template <
class Goal,
class Result,
class Feedback>
107 Feedback getFeedback();
108 ACTION_STATUS getStatus();
109 bool isServerConnected();
110 bool sendGoal(Goal goal);
111 bool waitForResult(
unsigned long wait_time_us);
112 bool waitForServer(
unsigned long wait_time_us);
115 std::string shm_name;
120 pthread_mutex_t *goal_mutex;
121 pthread_cond_t *goal_condition;
122 uint64_t *goal_timestamp_us;
124 pthread_mutex_t *result_mutex;
125 pthread_cond_t *result_condition;
126 uint64_t *result_timestamp_us;
128 Feedback *feedback_ptr;
129 ACTION_STATUS *status_ptr;
130 uint64_t *cancel_timestamp_us;
132 uint64_t current_result_timestamp_usec;
139 template <
class Goal,
class Result,
class Feedback>
143 , shared_memory(nullptr)
144 , memory_ptr(nullptr)
146 if (!std::is_standard_layout<Goal>::value
147 || !std::is_standard_layout<Result>::value
148 || !std::is_standard_layout<Feedback>::value)
150 throw std::runtime_error(
"shm::ActionServer: Be setted not POD class!");
153 shared_memory =
new SharedMemoryPosix(shm_name, O_RDWR|O_CREAT, shm_perm);
154 shared_memory->connect( (
sizeof(pthread_mutex_t)+
sizeof(pthread_cond_t)+
sizeof(uint64_t)) * 2 +
sizeof(Goal) +
sizeof(Result) +
sizeof(Feedback) +
sizeof(ACTION_STATUS) +
sizeof(uint64_t));
155 if (shared_memory->isDisconnected())
157 throw std::runtime_error(
"shm::ActionServer: Cannot get memory!");
160 uint8_t *data_ptr = shared_memory->getPtr();
161 memory_ptr = data_ptr;
162 goal_mutex =
reinterpret_cast<pthread_mutex_t *
>(data_ptr);
163 data_ptr +=
sizeof(pthread_mutex_t);
164 goal_condition =
reinterpret_cast<pthread_cond_t *
>(data_ptr);
165 data_ptr +=
sizeof(pthread_cond_t);
166 goal_timestamp_us =
reinterpret_cast<uint64_t *
>(data_ptr);
167 data_ptr +=
sizeof(uint64_t);
168 goal_ptr =
reinterpret_cast<Goal *
>(data_ptr);
169 data_ptr +=
sizeof(Goal);
170 result_mutex =
reinterpret_cast<pthread_mutex_t *
>(data_ptr);
171 data_ptr +=
sizeof(pthread_mutex_t);
172 result_condition =
reinterpret_cast<pthread_cond_t *
>(data_ptr);
173 data_ptr +=
sizeof(pthread_cond_t);
174 result_timestamp_us =
reinterpret_cast<uint64_t *
>(data_ptr);
175 data_ptr +=
sizeof(uint64_t);
176 result_ptr =
reinterpret_cast<Result *
>(data_ptr);
177 data_ptr +=
sizeof(Result);
178 feedback_ptr =
reinterpret_cast<Feedback *
>(data_ptr);
179 data_ptr +=
sizeof(Feedback);
180 status_ptr =
reinterpret_cast<ACTION_STATUS *
>(data_ptr);
181 data_ptr +=
sizeof(ACTION_STATUS);
182 cancel_timestamp_us =
reinterpret_cast<uint64_t *
>(data_ptr);
184 initializeExclusiveAccess();
186 *status_ptr = SUCCEEDED;
189 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
190 *cancel_timestamp_us = ((uint64_t) ts.tv_sec * 1000000L) + ((uint64_t) ts.tv_nsec / 1000L);
191 start_timestamp_us = *cancel_timestamp_us;
192 *goal_timestamp_us = *cancel_timestamp_us;
193 *result_timestamp_us = *cancel_timestamp_us;
195 current_goal_timestamp_usec = *goal_timestamp_us;
198 template <
class Goal,
class Result,
class Feedback>
199 ActionServer<Goal, Result, Feedback>::~ActionServer()
201 shared_memory->disconnect();
202 if (shared_memory !=
nullptr)
204 delete shared_memory;
208 template <
class Goal,
class Result,
class Feedback>
210 ActionServer<Goal, Result, Feedback>::initializeExclusiveAccess()
212 pthread_condattr_t goal_cond_attr;
213 pthread_condattr_init(&goal_cond_attr);
214 pthread_condattr_setpshared(&goal_cond_attr, PTHREAD_PROCESS_SHARED);
215 pthread_cond_init(goal_condition, &goal_cond_attr);
216 pthread_condattr_destroy(&goal_cond_attr);
218 pthread_mutexattr_t goal_m_attr;
219 pthread_mutexattr_init(&goal_m_attr);
220 pthread_mutexattr_setpshared(&goal_m_attr, PTHREAD_PROCESS_SHARED);
221 pthread_mutex_init(goal_mutex, &goal_m_attr);
222 pthread_mutexattr_destroy(&goal_m_attr);
224 pthread_condattr_t result_cond_attr;
225 pthread_condattr_init(&result_cond_attr);
226 pthread_condattr_setpshared(&result_cond_attr, PTHREAD_PROCESS_SHARED);
227 pthread_cond_init(result_condition, &result_cond_attr);
228 pthread_condattr_destroy(&result_cond_attr);
230 pthread_mutexattr_t result_m_attr;
231 pthread_mutexattr_init(&result_m_attr);
232 pthread_mutexattr_setpshared(&result_m_attr, PTHREAD_PROCESS_SHARED);
233 pthread_mutex_init(result_mutex, &result_m_attr);
234 pthread_mutexattr_destroy(&result_m_attr);
237 template <
class Goal,
class Result,
class Feedback>
239 ActionServer<Goal, Result, Feedback>::waitNewGoalAvailable()
241 while (current_goal_timestamp_usec >= *goal_timestamp_us)
244 pthread_mutex_lock(goal_mutex);
245 pthread_cond_wait(goal_condition, goal_mutex);
246 pthread_mutex_unlock(goal_mutex);
250 template <
class Goal,
class Result,
class Feedback>
252 ActionServer<Goal, Result, Feedback>::acceptNewGoal()
254 *status_ptr = ACTIVE;
256 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
257 start_timestamp_us = ((uint64_t) ts.tv_sec * 1000000L) + ((uint64_t) ts.tv_nsec / 1000L);
258 current_goal_timestamp_usec = *goal_timestamp_us;
263 template <
class Goal,
class Result,
class Feedback>
265 ActionServer<Goal, Result, Feedback>::rejectNewGoal()
267 *status_ptr = REJECTED;
268 current_goal_timestamp_usec = *goal_timestamp_us;
269 pthread_cond_broadcast(result_condition);
272 template <
class Goal,
class Result,
class Feedback>
274 ActionServer<Goal, Result, Feedback>::isPreemptRequested()
276 if (start_timestamp_us < *cancel_timestamp_us)
283 template <
class Goal,
class Result,
class Feedback>
285 ActionServer<Goal, Result, Feedback>::setPreempted()
287 *status_ptr = PREEMPTED;
290 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
291 *result_timestamp_us = ((uint64_t) ts.tv_sec * 1000000L) + ((uint64_t) ts.tv_nsec / 1000L);
293 pthread_cond_broadcast(result_condition);
296 template <
class Goal,
class Result,
class Feedback>
298 ActionServer<Goal, Result, Feedback>::publishResult(
const Result& result)
300 *result_ptr = result;
301 *status_ptr = SUCCEEDED;
304 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
305 *result_timestamp_us = ((uint64_t) ts.tv_sec * 1000000L) + ((uint64_t) ts.tv_nsec / 1000L);
307 pthread_cond_broadcast(result_condition);
310 template <
class Goal,
class Result,
class Feedback>
312 ActionServer<Goal, Result, Feedback>::publishFeedback(
const Feedback& feedback)
314 *feedback_ptr = feedback;
318 template <
class Goal,
class Result,
class Feedback>
319 ActionClient<Goal, Result, Feedback>::ActionClient(std::string name)
321 , shared_memory(nullptr)
323 if (!std::is_standard_layout<Goal>::value
324 || !std::is_standard_layout<Result>::value
325 || !std::is_standard_layout<Feedback>::value)
327 throw std::runtime_error(
"shm::ActionClient: Be setted not POD class!");
329 shared_memory =
new SharedMemoryPosix(shm_name, O_RDWR,
static_cast<PERM>(0));
332 template <
class Goal,
class Result,
class Feedback>
333 ActionClient<Goal, Result, Feedback>::~ActionClient()
335 if (shared_memory !=
nullptr)
337 delete shared_memory;
341 template <
class Goal,
class Result,
class Feedback>
343 ActionClient<Goal, Result, Feedback>::isServerConnected()
346 if (shared_memory->isDisconnected())
348 shared_memory->connect();
349 if (shared_memory->isDisconnected())
353 uint8_t *data_ptr = shared_memory->getPtr();
354 memory_ptr = data_ptr;
355 goal_mutex =
reinterpret_cast<pthread_mutex_t *
>(data_ptr);
356 data_ptr +=
sizeof(pthread_mutex_t);
357 goal_condition =
reinterpret_cast<pthread_cond_t *
>(data_ptr);
358 data_ptr +=
sizeof(pthread_cond_t);
359 goal_timestamp_us =
reinterpret_cast<uint64_t *
>(data_ptr);
360 data_ptr +=
sizeof(uint64_t);
361 goal_ptr =
reinterpret_cast<Goal *
>(data_ptr);
362 data_ptr +=
sizeof(Goal);
363 result_mutex =
reinterpret_cast<pthread_mutex_t *
>(data_ptr);
364 data_ptr +=
sizeof(pthread_mutex_t);
365 result_condition =
reinterpret_cast<pthread_cond_t *
>(data_ptr);
366 data_ptr +=
sizeof(pthread_cond_t);
367 result_timestamp_us =
reinterpret_cast<uint64_t *
>(data_ptr);
368 data_ptr +=
sizeof(uint64_t);
369 result_ptr =
reinterpret_cast<Result *
>(data_ptr);
370 data_ptr +=
sizeof(Result);
371 feedback_ptr =
reinterpret_cast<Feedback *
>(data_ptr);
372 data_ptr +=
sizeof(Feedback);
373 status_ptr =
reinterpret_cast<ACTION_STATUS *
>(data_ptr);
374 data_ptr +=
sizeof(ACTION_STATUS);
375 cancel_timestamp_us =
reinterpret_cast<uint64_t *
>(data_ptr);
381 template <
class Goal,
class Result,
class Feedback>
383 ActionClient<Goal, Result, Feedback>::sendGoal(Goal goal)
386 if (!(isServerConnected()))
391 current_result_timestamp_usec = *result_timestamp_us;
396 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
397 *goal_timestamp_us = ((uint64_t) ts.tv_sec * 1000000L) + ((uint64_t) ts.tv_nsec / 1000L);
398 pthread_cond_broadcast(goal_condition);
403 template <
class Goal,
class Result,
class Feedback>
405 ActionClient<Goal, Result, Feedback>::getResult()
410 template <
class Goal,
class Result,
class Feedback>
412 ActionClient<Goal, Result, Feedback>::getFeedback()
414 return *feedback_ptr;
417 template <
class Goal,
class Result,
class Feedback>
419 ActionClient<Goal, Result, Feedback>::getStatus()
424 template <
class Goal,
class Result,
class Feedback>
426 ActionClient<Goal, Result, Feedback>::cancelGoal()
429 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
430 *cancel_timestamp_us = ((uint64_t) ts.tv_sec * 1000000L) + ((uint64_t) ts.tv_nsec / 1000L);
433 template <
class Goal,
class Result,
class Feedback>
435 ActionClient<Goal, Result, Feedback>::waitForResult(
unsigned long wait_time_us)
438 long sec =
static_cast<long>(wait_time_us / 1000000);
439 long mod_sec =
static_cast<long>(wait_time_us % 1000000);
440 clock_gettime(CLOCK_REALTIME, &ts);
442 ts.tv_nsec+= mod_sec * 1000;
443 if (1000000000 <= ts.tv_nsec)
445 ts.tv_nsec -= 1000000000;
449 while (current_result_timestamp_usec >= *result_timestamp_us)
452 pthread_mutex_lock(result_mutex);
453 int ret = pthread_cond_timedwait(result_condition, result_mutex, &ts);
454 pthread_mutex_unlock(result_mutex);
455 if (ret == ETIMEDOUT)
463 template <
class Goal,
class Result,
class Feedback>
465 ActionClient<Goal, Result, Feedback>::waitForServer(uint64_t wait_time_us)
467 static const uint64_t SLEEP_PERIOD_us = 100000;
469 if (isServerConnected())
474 for (uint64_t time_index = 0; time_index < wait_time_us / SLEEP_PERIOD_us; time_index++)
476 if (isServerConnected())
480 usleep(SLEEP_PERIOD_us);
490 #endif //__SHM_ACTION_LIB_H__