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));
156 if (this->wait_result_holding_) {this->wait_result_dirty_ =
true;}
159 for (auto key_event_pair : inner_subscription->get_event_handlers()) {
160 auto event = key_event_pair.second;
161 auto local_subscription = inner_subscription;
162 bool already_in_use =
163 local_subscription->exchange_in_use_by_wait_set_state(event.get(), true);
164 if (already_in_use) {
165 throw std::runtime_error(
"subscription event already associated with a wait set");
167 this->storage_add_waitable(std::move(event), std::move(local_subscription));
168 if (this->wait_result_holding_) {this->wait_result_dirty_ = true;}
172 auto local_subscription = inner_subscription;
173 auto waitable = inner_subscription->get_intra_process_waitable();
174 if (nullptr != waitable) {
175 bool already_in_use = local_subscription->exchange_in_use_by_wait_set_state(
178 if (already_in_use) {
179 throw std::runtime_error(
180 "subscription intra-process waitable already associated with a wait set");
182 this->storage_add_waitable(
183 std::move(inner_subscription->get_intra_process_waitable()),
184 std::move(local_subscription));
185 if (this->wait_result_holding_) {this->wait_result_dirty_ = true;}
209 std::shared_ptr<rclcpp::SubscriptionBase> subscription,
212 if (
nullptr == subscription) {
213 throw std::invalid_argument(
"subscription is nullptr");
216 this->sync_remove_subscription(
217 std::move(subscription),
220 std::shared_ptr<rclcpp::SubscriptionBase> && inner_subscription,
227 auto local_subscription = inner_subscription;
228 this->storage_remove_subscription(std::move(local_subscription));
229 inner_subscription->exchange_in_use_by_wait_set_state(inner_subscription.get(), false);
230 if (this->wait_result_holding_) {this->wait_result_dirty_ = true;}
233 for (auto key_event_pair : inner_subscription->get_event_handlers()) {
234 auto event = key_event_pair.second;
235 auto local_subscription = inner_subscription;
236 this->storage_remove_waitable(std::move(event));
237 local_subscription->exchange_in_use_by_wait_set_state(
238 key_event_pair.second.get(), false);
239 if (this->wait_result_holding_) {this->wait_result_dirty_ = true;}
243 auto local_waitable = inner_subscription->get_intra_process_waitable();
244 if (nullptr != local_waitable) {
246 auto waitable = local_waitable;
247 this->storage_remove_waitable(std::move(local_waitable));
248 inner_subscription->exchange_in_use_by_wait_set_state(waitable.get(), false);
249 if (this->wait_result_holding_) {this->wait_result_dirty_ = true;}
285 if (
nullptr == guard_condition) {
286 throw std::invalid_argument(
"guard_condition is nullptr");
289 this->sync_add_guard_condition(
290 std::move(guard_condition),
291 [
this](std::shared_ptr<rclcpp::GuardCondition> && inner_guard_condition) {
292 bool already_in_use = inner_guard_condition->exchange_in_use_by_wait_set_state(
true);
293 if (already_in_use) {
294 throw std::runtime_error(
"guard condition already in use by another wait set");
299 this->storage_add_guard_condition(std::move(inner_guard_condition));
300 if (this->wait_result_holding_) {this->wait_result_dirty_ =
true;}
326 if (
nullptr == guard_condition) {
327 throw std::invalid_argument(
"guard_condition is nullptr");
330 this->sync_remove_guard_condition(
331 std::move(guard_condition),
332 [
this](std::shared_ptr<rclcpp::GuardCondition> && inner_guard_condition) {
336 auto local_guard_condition = inner_guard_condition;
337 this->storage_remove_guard_condition(std::move(local_guard_condition));
338 inner_guard_condition->exchange_in_use_by_wait_set_state(
false);
339 if (this->wait_result_holding_) {this->wait_result_dirty_ =
true;}
356 if (
nullptr == timer) {
357 throw std::invalid_argument(
"timer is nullptr");
360 this->sync_add_timer(
362 [
this](std::shared_ptr<rclcpp::TimerBase> && inner_timer) {
363 bool already_in_use = inner_timer->exchange_in_use_by_wait_set_state(
true);
364 if (already_in_use) {
365 throw std::runtime_error(
"timer already in use by another wait set");
370 this->storage_add_timer(std::move(inner_timer));
371 if (this->wait_result_holding_) {this->wait_result_dirty_ =
true;}
387 if (
nullptr == timer) {
388 throw std::invalid_argument(
"timer is nullptr");
391 this->sync_remove_timer(
393 [
this](std::shared_ptr<rclcpp::TimerBase> && inner_timer) {
397 auto local_timer = inner_timer;
398 this->storage_remove_timer(std::move(local_timer));
399 inner_timer->exchange_in_use_by_wait_set_state(
false);
400 if (this->wait_result_holding_) {this->wait_result_dirty_ =
true;}
417 if (
nullptr == client) {
418 throw std::invalid_argument(
"client is nullptr");
421 this->sync_add_client(
423 [
this](std::shared_ptr<rclcpp::ClientBase> && inner_client) {
424 bool already_in_use = inner_client->exchange_in_use_by_wait_set_state(
true);
425 if (already_in_use) {
426 throw std::runtime_error(
"client already in use by another wait set");
431 this->storage_add_client(std::move(inner_client));
432 if (this->wait_result_holding_) {this->wait_result_dirty_ =
true;}
448 if (
nullptr == client) {
449 throw std::invalid_argument(
"client is nullptr");
452 this->sync_remove_client(
454 [
this](std::shared_ptr<rclcpp::ClientBase> && inner_client) {
458 auto local_client = inner_client;
459 this->storage_remove_client(std::move(local_client));
460 inner_client->exchange_in_use_by_wait_set_state(
false);
461 if (this->wait_result_holding_) {this->wait_result_dirty_ =
true;}
478 if (
nullptr == service) {
479 throw std::invalid_argument(
"service is nullptr");
482 this->sync_add_service(
484 [
this](std::shared_ptr<rclcpp::ServiceBase> && inner_service) {
485 bool already_in_use = inner_service->exchange_in_use_by_wait_set_state(
true);
486 if (already_in_use) {
487 throw std::runtime_error(
"service already in use by another wait set");
492 this->storage_add_service(std::move(inner_service));
493 if (this->wait_result_holding_) {this->wait_result_dirty_ =
true;}
509 if (
nullptr == service) {
510 throw std::invalid_argument(
"service is nullptr");
513 this->sync_remove_service(
515 [
this](std::shared_ptr<rclcpp::ServiceBase> && inner_service) {
519 auto local_service = inner_service;
520 this->storage_remove_service(std::move(local_service));
521 inner_service->exchange_in_use_by_wait_set_state(
false);
522 if (this->wait_result_holding_) {this->wait_result_dirty_ =
true;}
552 std::shared_ptr<rclcpp::Waitable> waitable,
553 std::shared_ptr<void> associated_entity =
nullptr)
555 if (
nullptr == waitable) {
556 throw std::invalid_argument(
"waitable is nullptr");
559 this->sync_add_waitable(
561 std::move(associated_entity),
563 std::shared_ptr<rclcpp::Waitable> && inner_waitable,
564 std::shared_ptr<void> && associated_entity)
566 bool already_in_use = inner_waitable->exchange_in_use_by_wait_set_state(
true);
567 if (already_in_use) {
568 throw std::runtime_error(
"waitable already in use by another wait set");
573 this->storage_add_waitable(std::move(inner_waitable), std::move(associated_entity));
574 if (this->wait_result_holding_) {this->wait_result_dirty_ =
true;}
590 if (
nullptr == waitable) {
591 throw std::invalid_argument(
"waitable is nullptr");
594 this->sync_remove_waitable(
596 [
this](std::shared_ptr<rclcpp::Waitable> && inner_waitable) {
600 auto local_waitable = inner_waitable;
601 this->storage_remove_waitable(std::move(local_waitable));
602 inner_waitable->exchange_in_use_by_wait_set_state(
false);
603 if (this->wait_result_holding_) {this->wait_result_dirty_ =
true;}
627 this->sync_prune_deleted_entities(
631 this->storage_prune_deleted_entities();
676 template<
class Rep =
int64_t,
class Period = std::milli>
679 wait(std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1))
681 auto time_to_wait_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(time_to_wait);
684 this->storage_acquire_ownerships();
685 RCPPUTILS_SCOPE_EXIT({this->storage_release_ownerships();});
688 return this->
template sync_wait<WaitResult<WaitSetTemplate>>(
694 this->storage_rebuild_rcl_wait_set(
696 this->get_extra_guard_conditions()
702 return this->storage_get_rcl_wait_set();
707 switch (wait_result_kind) {
708 case WaitResultKind::Ready:
710 case WaitResultKind::Timeout:
712 case WaitResultKind::Empty:
714 case WaitResultKind::Invalid:
715 auto msg =
"invalid WaitResultKind with value: " + std::to_string(wait_result_kind);
716 throw std::runtime_error(msg);
719 throw std::runtime_error(
"unreachable code in wait result kind switch");
737 wait_result_acquire()
739 if (wait_result_holding_) {
740 throw std::runtime_error(
"wait_result_acquire() called while already holding");
742 wait_result_holding_ =
true;
743 wait_result_dirty_ =
false;
745 this->sync_wait_result_acquire();
755 wait_result_release()
757 if (!wait_result_holding_) {
758 throw std::runtime_error(
"wait_result_release() called while not holding");
760 wait_result_holding_ =
false;
761 wait_result_dirty_ =
false;
763 this->sync_wait_result_release();
766 bool wait_result_holding_ =
false;
767 bool wait_result_dirty_ =
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.