15 #ifndef RCLCPP__WAIT_SET_TEMPLATE_HPP_
16 #define RCLCPP__WAIT_SET_TEMPLATE_HPP_
23 #include "rcpputils/scope_exit.hpp"
25 #include "rclcpp/client.hpp"
26 #include "rclcpp/context.hpp"
27 #include "rclcpp/contexts/default_context.hpp"
28 #include "rclcpp/guard_condition.hpp"
29 #include "rclcpp/macros.hpp"
30 #include "rclcpp/service.hpp"
31 #include "rclcpp/subscription_base.hpp"
32 #include "rclcpp/subscription_wait_set_mask.hpp"
33 #include "rclcpp/timer.hpp"
34 #include "rclcpp/visibility_control.hpp"
35 #include "rclcpp/wait_result.hpp"
36 #include "rclcpp/waitable.hpp"
46 template<
class SynchronizationPolicy,
class StoragePolicy>
47 class WaitSetTemplate final :
private SynchronizationPolicy,
private StoragePolicy
52 using typename StoragePolicy::SubscriptionEntry;
53 using typename StoragePolicy::WaitableEntry;
72 const typename StoragePolicy::SubscriptionsIterable & subscriptions = {},
73 const typename StoragePolicy::GuardConditionsIterable & guard_conditions = {},
74 const typename StoragePolicy::TimersIterable & timers = {},
75 const typename StoragePolicy::ClientsIterable & clients = {},
76 const typename StoragePolicy::ServicesIterable & services = {},
77 const typename StoragePolicy::WaitablesIterable & waitables = {},
78 rclcpp::Context::SharedPtr context =
79 rclcpp::contexts::get_global_default_context())
80 : SynchronizationPolicy(context),
85 this->get_extra_guard_conditions(),
103 return this->storage_get_rcl_wait_set();
131 std::shared_ptr<rclcpp::SubscriptionBase> subscription,
134 if (
nullptr == subscription) {
135 throw std::invalid_argument(
"subscription is nullptr");
138 this->sync_add_subscription(
139 std::move(subscription),
142 std::shared_ptr<rclcpp::SubscriptionBase> && inner_subscription,
149 auto local_subscription = inner_subscription;
150 bool already_in_use =
151 local_subscription->exchange_in_use_by_wait_set_state(local_subscription.get(), true);
152 if (already_in_use) {
153 throw std::runtime_error(
"subscription already associated with a wait set");
155 this->storage_add_subscription(std::move(local_subscription));
158 for (auto key_event_pair : inner_subscription->get_event_handlers()) {
159 auto event = key_event_pair.second;
160 auto local_subscription = inner_subscription;
161 bool already_in_use =
162 local_subscription->exchange_in_use_by_wait_set_state(event.get(), true);
163 if (already_in_use) {
164 throw std::runtime_error(
"subscription event already associated with a wait set");
166 this->storage_add_waitable(std::move(event), std::move(local_subscription));
170 auto local_subscription = inner_subscription;
171 auto waitable = inner_subscription->get_intra_process_waitable();
172 if (nullptr != waitable) {
173 bool already_in_use = local_subscription->exchange_in_use_by_wait_set_state(
176 if (already_in_use) {
177 throw std::runtime_error(
178 "subscription intra-process waitable already associated with a wait set");
180 this->storage_add_waitable(
181 std::move(inner_subscription->get_intra_process_waitable()),
182 std::move(local_subscription));
206 std::shared_ptr<rclcpp::SubscriptionBase> subscription,
209 if (
nullptr == subscription) {
210 throw std::invalid_argument(
"subscription is nullptr");
213 this->sync_remove_subscription(
214 std::move(subscription),
217 std::shared_ptr<rclcpp::SubscriptionBase> && inner_subscription,
224 auto local_subscription = inner_subscription;
225 local_subscription->exchange_in_use_by_wait_set_state(local_subscription.get(), false);
226 this->storage_remove_subscription(std::move(local_subscription));
229 for (auto key_event_pair : inner_subscription->get_event_handlers()) {
230 auto event = key_event_pair.second;
231 auto local_subscription = inner_subscription;
232 local_subscription->exchange_in_use_by_wait_set_state(event.get(), false);
233 this->storage_remove_waitable(std::move(event));
237 auto local_waitable = inner_subscription->get_intra_process_waitable();
238 if (nullptr != local_waitable) {
240 inner_subscription->exchange_in_use_by_wait_set_state(local_waitable.get(), false);
241 this->storage_remove_waitable(std::move(local_waitable));
277 if (
nullptr == guard_condition) {
278 throw std::invalid_argument(
"guard_condition is nullptr");
281 this->sync_add_guard_condition(
282 std::move(guard_condition),
283 [
this](std::shared_ptr<rclcpp::GuardCondition> && inner_guard_condition) {
284 bool already_in_use = inner_guard_condition->exchange_in_use_by_wait_set_state(
true);
285 if (already_in_use) {
286 throw std::runtime_error(
"guard condition already in use by another wait set");
291 this->storage_add_guard_condition(std::move(inner_guard_condition));
317 if (
nullptr == guard_condition) {
318 throw std::invalid_argument(
"guard_condition is nullptr");
321 this->sync_remove_guard_condition(
322 std::move(guard_condition),
323 [
this](std::shared_ptr<rclcpp::GuardCondition> && inner_guard_condition) {
324 inner_guard_condition->exchange_in_use_by_wait_set_state(
false);
328 this->storage_remove_guard_condition(std::move(inner_guard_condition));
345 if (
nullptr == timer) {
346 throw std::invalid_argument(
"timer is nullptr");
349 this->sync_add_timer(
351 [
this](std::shared_ptr<rclcpp::TimerBase> && inner_timer) {
352 bool already_in_use = inner_timer->exchange_in_use_by_wait_set_state(
true);
353 if (already_in_use) {
354 throw std::runtime_error(
"timer already in use by another wait set");
359 this->storage_add_timer(std::move(inner_timer));
375 if (
nullptr == timer) {
376 throw std::invalid_argument(
"timer is nullptr");
379 this->sync_remove_timer(
381 [
this](std::shared_ptr<rclcpp::TimerBase> && inner_timer) {
382 inner_timer->exchange_in_use_by_wait_set_state(
false);
386 this->storage_remove_timer(std::move(inner_timer));
403 if (
nullptr == client) {
404 throw std::invalid_argument(
"client is nullptr");
407 this->sync_add_client(
409 [
this](std::shared_ptr<rclcpp::ClientBase> && inner_client) {
410 bool already_in_use = inner_client->exchange_in_use_by_wait_set_state(
true);
411 if (already_in_use) {
412 throw std::runtime_error(
"client already in use by another wait set");
417 this->storage_add_client(std::move(inner_client));
433 if (
nullptr == client) {
434 throw std::invalid_argument(
"client is nullptr");
437 this->sync_remove_client(
439 [
this](std::shared_ptr<rclcpp::ClientBase> && inner_client) {
440 inner_client->exchange_in_use_by_wait_set_state(
false);
444 this->storage_remove_client(std::move(inner_client));
461 if (
nullptr == service) {
462 throw std::invalid_argument(
"service is nullptr");
465 this->sync_add_service(
467 [
this](std::shared_ptr<rclcpp::ServiceBase> && inner_service) {
468 bool already_in_use = inner_service->exchange_in_use_by_wait_set_state(
true);
469 if (already_in_use) {
470 throw std::runtime_error(
"service already in use by another wait set");
475 this->storage_add_service(std::move(inner_service));
491 if (
nullptr == service) {
492 throw std::invalid_argument(
"service is nullptr");
495 this->sync_remove_service(
497 [
this](std::shared_ptr<rclcpp::ServiceBase> && inner_service) {
498 inner_service->exchange_in_use_by_wait_set_state(
false);
502 this->storage_remove_service(std::move(inner_service));
532 std::shared_ptr<rclcpp::Waitable> waitable,
533 std::shared_ptr<void> associated_entity =
nullptr)
535 if (
nullptr == waitable) {
536 throw std::invalid_argument(
"waitable is nullptr");
539 this->sync_add_waitable(
541 std::move(associated_entity),
543 std::shared_ptr<rclcpp::Waitable> && inner_waitable,
544 std::shared_ptr<void> && associated_entity)
546 bool already_in_use = inner_waitable->exchange_in_use_by_wait_set_state(
true);
547 if (already_in_use) {
548 throw std::runtime_error(
"waitable already in use by another wait set");
553 this->storage_add_waitable(std::move(inner_waitable), std::move(associated_entity));
569 if (
nullptr == waitable) {
570 throw std::invalid_argument(
"waitable is nullptr");
573 this->sync_remove_waitable(
575 [
this](std::shared_ptr<rclcpp::Waitable> && inner_waitable) {
576 inner_waitable->exchange_in_use_by_wait_set_state(
false);
580 this->storage_remove_waitable(std::move(inner_waitable));
604 this->sync_prune_deleted_entities(
608 this->storage_prune_deleted_entities();
653 template<
class Rep =
int64_t,
class Period = std::milli>
656 wait(std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1))
658 auto time_to_wait_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(time_to_wait);
661 this->storage_acquire_ownerships();
662 RCPPUTILS_SCOPE_EXIT({this->storage_release_ownerships();});
665 return this->
template sync_wait<WaitResult<WaitSetTemplate>>(
671 this->storage_rebuild_rcl_wait_set(
673 this->get_extra_guard_conditions()
679 return this->storage_get_rcl_wait_set();
684 switch (wait_result_kind) {
685 case WaitResultKind::Ready:
687 case WaitResultKind::Timeout:
689 case WaitResultKind::Empty:
692 auto msg =
"unknown WaitResultKind with value: " + std::to_string(wait_result_kind);
693 throw std::runtime_error(msg);
712 wait_result_acquire()
714 if (wait_result_holding_) {
715 throw std::runtime_error(
"wait_result_acquire() called while already holding");
717 wait_result_holding_ =
true;
719 this->sync_wait_result_acquire();
721 this->storage_acquire_ownerships();
731 wait_result_release()
733 if (!wait_result_holding_) {
734 throw std::runtime_error(
"wait_result_release() called while not holding");
736 wait_result_holding_ =
false;
738 this->storage_release_ownerships();
740 this->sync_wait_result_release();
743 bool wait_result_holding_ =
false;
Options used to determine what parts of a subscription get added to or removed from a wait set.
bool include_events
If true, include any events attached to the subscription.
bool include_subscription
If true, include the actual subscription.
bool include_intra_process_waitable
If true, include the waitable used to handle intra process communication.
Interface for introspecting a wait set after waiting on it.
Encapsulates sets of waitable items which can be waited on as a group.
void prune_deleted_entities()
Remove any destroyed entities from the wait set.
void add_guard_condition(std::shared_ptr< rclcpp::GuardCondition > guard_condition)
Add a guard condition to this wait set.
void remove_waitable(std::shared_ptr< rclcpp::Waitable > waitable)
Remove a waitable from this wait set.
void add_service(std::shared_ptr< rclcpp::ServiceBase > service)
Add a service to this wait set.
void add_subscription(std::shared_ptr< rclcpp::SubscriptionBase > subscription, rclcpp::SubscriptionWaitSetMask mask={})
Add a subscription to this wait set.
void remove_client(std::shared_ptr< rclcpp::ClientBase > client)
Remove a client from this wait set.
WaitSetTemplate(const typename StoragePolicy::SubscriptionsIterable &subscriptions={}, const typename StoragePolicy::GuardConditionsIterable &guard_conditions={}, const typename StoragePolicy::TimersIterable &timers={}, const typename StoragePolicy::ClientsIterable &clients={}, const typename StoragePolicy::ServicesIterable &services={}, const typename StoragePolicy::WaitablesIterable &waitables={}, rclcpp::Context::SharedPtr context=rclcpp::contexts::get_global_default_context())
Construct a wait set with optional initial waitable entities and optional custom context.
void add_waitable(std::shared_ptr< rclcpp::Waitable > waitable, std::shared_ptr< void > associated_entity=nullptr)
Add a waitable to this wait set.
void remove_subscription(std::shared_ptr< rclcpp::SubscriptionBase > subscription, rclcpp::SubscriptionWaitSetMask mask={})
Remove a subscription from this wait set.
void add_client(std::shared_ptr< rclcpp::ClientBase > client)
Add a client to this wait set.
void remove_guard_condition(std::shared_ptr< rclcpp::GuardCondition > guard_condition)
Remove a guard condition from this wait set.
void remove_timer(std::shared_ptr< rclcpp::TimerBase > timer)
Remove a timer from this wait set.
RCUTILS_WARN_UNUSED WaitResult< WaitSetTemplate > wait(std::chrono::duration< Rep, Period > time_to_wait=std::chrono::duration< Rep, Period >(-1))
Wait for any of the entities in the wait set to be ready, or a period of time to pass.
void add_timer(std::shared_ptr< rclcpp::TimerBase > timer)
Add a timer to this wait set.
void remove_service(std::shared_ptr< rclcpp::ServiceBase > service)
Remove a service from this wait set.
const rcl_wait_set_t & get_rcl_wait_set() const
Return the internal rcl wait set object.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
Container for subscription's, guard condition's, etc to be waited on.