23 #include <type_traits>
28 #include "rcl/error_handling.h"
29 #include "rclcpp/executors/executor_notify_waitable.hpp"
30 #include "rclcpp/subscription_wait_set_mask.hpp"
31 #include "rcpputils/scope_exit.hpp"
33 #include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
34 #include "rclcpp/exceptions.hpp"
35 #include "rclcpp/executor.hpp"
36 #include "rclcpp/guard_condition.hpp"
37 #include "rclcpp/node.hpp"
38 #include "rclcpp/utilities.hpp"
40 #include "rcutils/logging_macros.h"
42 #include "tracetools/tracetools.h"
44 using namespace std::chrono_literals;
54 Executor::Executor(
const std::shared_ptr<rclcpp::Context> & context)
56 cancel_requested_(false),
58 entities_need_rebuild_(true),
60 wait_set_({}, {}, {}, {}, {}, {}, context)
66 cancel_requested_(false),
69 context_(options.context),
70 notify_waitable_(std::make_shared<
rclcpp::executors::ExecutorNotifyWaitable>(
72 this->entities_need_rebuild_.store(
true);
74 entities_need_rebuild_(
true),
75 collector_(notify_waitable_),
76 wait_set_({}, {}, {}, {}, {}, {}, options.context),
77 current_notify_waitable_(notify_waitable_),
78 impl_(std::make_unique<rclcpp::ExecutorImplementation>())
80 shutdown_callback_handle_ = context_->add_on_shutdown_callback(
81 [weak_gc = std::weak_ptr<rclcpp::GuardCondition>{shutdown_guard_condition_}]() {
82 auto strong_gc = weak_gc.lock();
88 notify_waitable_->add_guard_condition(interrupt_guard_condition_);
89 notify_waitable_->add_guard_condition(shutdown_guard_condition_);
98 std::lock_guard<std::mutex> guard(mutex_);
102 current_collection_.timers.update(
104 [
this](
auto timer) {wait_set_.remove_timer(std::move(timer));});
106 current_collection_.subscriptions.update(
108 [
this](
auto subscription) {
109 wait_set_.remove_subscription(std::move(subscription), kDefaultSubscriptionMask);
112 current_collection_.clients.update(
114 [
this](
auto client) {wait_set_.remove_client(std::move(client));});
116 current_collection_.services.update(
118 [
this](
auto service) {wait_set_.remove_service(std::move(service));});
120 current_collection_.guard_conditions.update(
122 [
this](
auto guard_condition) {wait_set_.remove_guard_condition(std::move(guard_condition));});
124 current_collection_.waitables.update(
126 [
this](
auto waitable) {wait_set_.remove_waitable(std::move(waitable));});
130 RCUTILS_LOG_ERROR_NAMED(
132 "failed to remove registered on_shutdown callback");
140 this->entities_need_rebuild_.store(
true);
142 if (!
spinning.load() && entities_need_rebuild_.exchange(
false)) {
143 std::lock_guard<std::mutex> guard(mutex_);
152 std::vector<rclcpp::CallbackGroup::WeakPtr>
159 std::vector<rclcpp::CallbackGroup::WeakPtr>
166 std::vector<rclcpp::CallbackGroup::WeakPtr>
175 const rclcpp::CallbackGroup::SharedPtr & group_ptr,
176 [[maybe_unused]]
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
184 throw std::runtime_error(
186 "Failed to handle entities update on callback group add: ") + ex.what());
192 const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
195 if (node_ptr->get_context() !=
context_) {
196 throw std::runtime_error(
197 "add_node() called with a node with a different context from this executor");
205 throw std::runtime_error(
207 "Failed to handle entities update on node add: ") + ex.what());
213 const rclcpp::CallbackGroup::SharedPtr & group_ptr,
221 throw std::runtime_error(
223 "Failed to handle entities update on callback group remove: ") + ex.what());
230 this->
add_node(node_ptr->get_node_base_interface(), notify);
235 const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
243 throw std::runtime_error(
245 "Failed to handle entities update on node remove: ") + ex.what());
252 this->
remove_node(node_ptr->get_node_base_interface(), notify);
257 const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node,
258 std::chrono::nanoseconds timeout)
268 std::chrono::nanoseconds timeout,
269 const std::function<std::future_status(std::chrono::nanoseconds wait_time)> & wait_for_future)
276 std::future_status status = wait_for_future(std::chrono::seconds(0));
277 if (status == std::future_status::ready) {
278 return FutureReturnCode::SUCCESS;
281 auto end_time = std::chrono::steady_clock::now();
282 std::chrono::nanoseconds timeout_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
284 if (timeout_ns > std::chrono::nanoseconds::zero()) {
285 end_time += timeout_ns;
287 std::chrono::nanoseconds timeout_left = timeout_ns;
290 throw std::runtime_error(
"spin_until_future_complete() called while already spinning");
292 RCPPUTILS_SCOPE_EXIT(
293 wait_result_.reset();
294 this->spinning.store(
false);
295 this->cancel_requested_.store(
false););
297 return FutureReturnCode::INTERRUPTED;
301 spin_once_impl(timeout_left);
304 status = wait_for_future(std::chrono::seconds(0));
305 if (status == std::future_status::ready) {
306 return FutureReturnCode::SUCCESS;
309 if (timeout_ns < std::chrono::nanoseconds::zero()) {
313 auto now = std::chrono::steady_clock::now();
314 if (now >= end_time) {
315 return FutureReturnCode::TIMEOUT;
318 timeout_left = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - now);
322 return FutureReturnCode::INTERRUPTED;
346 const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node,
347 std::chrono::nanoseconds max_duration)
356 const std::shared_ptr<rclcpp::Node> & node,
357 std::chrono::nanoseconds max_duration)
359 this->
spin_node_all(node->get_node_base_interface(), max_duration);
364 if (max_duration < 0ns) {
365 throw std::invalid_argument(
"max_duration must be greater than or equal to 0");
373 auto start = std::chrono::steady_clock::now();
374 auto max_duration_not_elapsed = [max_duration, start]() {
375 if (std::chrono::nanoseconds(0) == max_duration) {
378 }
else if (std::chrono::steady_clock::now() - start < max_duration) {
387 throw std::runtime_error(
"spin_some() called while already spinning");
389 RCPPUTILS_SCOPE_EXIT(
390 wait_result_.reset();
391 this->spinning.store(
false);
392 this->cancel_requested_.store(
false););
400 wait_result_.reset();
402 bool entity_states_fully_polled =
true;
404 if (entities_need_rebuild_) {
408 entity_states_fully_polled =
false;
433 entity_states_fully_polled =
false;
436 wait_result_.reset();
438 if (entity_states_fully_polled) {
448 entity_states_fully_polled =
true;
449 if (entities_need_rebuild_) {
453 entity_states_fully_polled =
false;
463 Executor::spin_once_impl(std::chrono::nanoseconds timeout)
475 throw std::runtime_error(
"spin_once() called while already spinning");
477 RCPPUTILS_SCOPE_EXIT(
478 wait_result_.reset();
479 this->spinning.store(
false);
480 this->cancel_requested_.store(
false););
484 spin_once_impl(timeout);
498 throw std::runtime_error(
499 std::string(
"Failed to trigger guard condition in cancel: ") + ex.what());
511 (
void(
"cannot execute an AnyExecutable without a valid callback group"),
512 any_exec.callback_group));
514 if (any_exec.timer) {
515 TRACETOOLS_TRACEPOINT(
516 rclcpp_executor_execute,
517 static_cast<const void *
>(any_exec.timer->get_timer_handle().get()));
520 if (any_exec.subscription) {
521 TRACETOOLS_TRACEPOINT(
522 rclcpp_executor_execute,
523 static_cast<const void *
>(any_exec.subscription->get_subscription_handle().get()));
526 if (any_exec.service) {
529 if (any_exec.client) {
532 if (any_exec.waitable) {
533 const std::shared_ptr<void> & const_data = any_exec.data;
534 any_exec.waitable->execute(const_data);
538 any_exec.callback_group->can_be_taken_from().store(
true);
541 template<
typename Taker,
typename Handler>
544 take_and_do_error_handling(
545 const char * action_description,
546 const char * topic_or_service_name,
548 Handler handle_action)
552 taken = take_action();
556 "executor %s '%s' unexpectedly failed: %s",
558 topic_or_service_name,
572 "executor %s '%s' failed to take anything",
574 topic_or_service_name);
586 switch (subscription->get_delivered_message_kind()) {
588 case rclcpp::DeliveredMessageKind::ROS_MESSAGE:
590 if (subscription->can_loan_messages()) {
594 void * loaned_msg =
nullptr;
597 take_and_do_error_handling(
598 "taking a loaned message from topic",
599 subscription->get_topic_name(),
602 rcl_ret_t ret = rcl_take_loaned_message(
603 subscription->get_subscription_handle().get(),
605 &message_info.get_rmw_message_info(),
607 TRACETOOLS_TRACEPOINT(rclcpp_take, static_cast<const void *>(loaned_msg));
608 if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
611 rclcpp::exceptions::throw_from_rcl_error(ret);
615 [&]() {subscription->handle_loaned_message(loaned_msg, message_info);});
616 if (
nullptr != loaned_msg) {
618 subscription->get_subscription_handle().get(), loaned_msg);
622 "rcl_return_loaned_message_from_subscription() failed for subscription on topic "
624 subscription->get_topic_name(), rcl_get_error_string().str);
627 loaned_msg =
nullptr;
632 std::shared_ptr<void> message = subscription->create_message();
633 take_and_do_error_handling(
634 "taking a message from topic",
635 subscription->get_topic_name(),
636 [&]() {return subscription->take_type_erased(message.get(), message_info);},
637 [&]() {subscription->handle_message(message, message_info);});
643 subscription->return_message(message);
649 case rclcpp::DeliveredMessageKind::SERIALIZED_MESSAGE:
653 std::shared_ptr<SerializedMessage> serialized_msg =
654 subscription->create_serialized_message();
655 take_and_do_error_handling(
656 "taking a serialized message from topic",
657 subscription->get_topic_name(),
658 [&]() {return subscription->take_serialized(*serialized_msg.get(), message_info);},
661 subscription->handle_serialized_message(serialized_msg, message_info);
663 subscription->return_serialized_message(serialized_msg);
669 case rclcpp::DeliveredMessageKind::DYNAMIC_MESSAGE:
671 throw std::runtime_error(
"Unimplemented");
674 case rclcpp::DeliveredMessageKind::INVALID:
676 throw std::runtime_error(
"Delivered message kind is not supported");
682 Executor::execute_timer(
683 const rclcpp::TimerBase::SharedPtr & timer,
684 const std::shared_ptr<void> & data_ptr)
686 timer->execute_callback(data_ptr);
692 auto request_header = service->create_request_header();
693 std::shared_ptr<void> request = service->create_request();
694 take_and_do_error_handling(
695 "taking a service server request from service",
696 service->get_service_name(),
697 [&]() {return service->take_type_erased_request(request.get(), *request_header);},
698 [&]() {service->handle_request(request_header, request);});
704 auto request_header = client->create_request_header();
705 std::shared_ptr<void> response = client->create_response();
706 take_and_do_error_handling(
707 "taking a service client response from service",
708 client->get_service_name(),
709 [&]() {return client->take_type_erased_response(response.get(), *request_header);},
710 [&]() {client->handle_response(request_header, response);});
717 this->wait_result_.reset();
723 rclcpp::executors::build_entities_collection(callback_groups, collection);
730 current_notify_waitable_ = std::make_shared<rclcpp::executors::ExecutorNotifyWaitable>(
732 auto notify_waitable = std::static_pointer_cast<rclcpp::Waitable>(current_notify_waitable_);
733 collection.
waitables.insert({notify_waitable.get(), {notify_waitable, {}}});
738 current_collection_.remove_expired_entities();
742 current_collection_.timers.
update(
744 [
this](
auto timer) {wait_set_.add_timer(std::move(timer));},
745 [
this](
auto timer) {wait_set_.remove_timer(std::move(timer));});
747 current_collection_.subscriptions.update(
749 [
this](
auto subscription) {
750 wait_set_.add_subscription(std::move(subscription), kDefaultSubscriptionMask);
752 [
this](
auto subscription) {
753 wait_set_.remove_subscription(std::move(subscription), kDefaultSubscriptionMask);
756 current_collection_.clients.update(
758 [
this](
auto client) {wait_set_.add_client(std::move(client));},
759 [
this](
auto client) {wait_set_.remove_client(std::move(client));});
761 current_collection_.services.update(
763 [
this](
auto service) {wait_set_.add_service(std::move(service));},
764 [
this](
auto service) {wait_set_.remove_service(std::move(service));});
766 current_collection_.guard_conditions.update(
768 [
this](
auto guard_condition) {wait_set_.add_guard_condition(std::move(guard_condition));},
769 [
this](
auto guard_condition) {wait_set_.remove_guard_condition(std::move(guard_condition));});
771 current_collection_.waitables.update(
773 [
this](
auto waitable) {wait_set_.add_waitable(std::move(waitable));},
774 [
this](
auto waitable) {wait_set_.remove_waitable(std::move(waitable));});
778 this->wait_set_.prune_deleted_entities();
784 TRACETOOLS_TRACEPOINT(rclcpp_executor_wait_for_work, timeout.count());
787 this->wait_result_.reset();
790 std::lock_guard<std::mutex> guard(mutex_);
792 if (this->entities_need_rebuild_.exchange(
false) || current_collection_.empty()) {
797 this->wait_result_.emplace(wait_set_.wait(timeout));
799 if (!this->wait_result_ || this->wait_result_->kind() == WaitResultKind::Empty) {
800 RCUTILS_LOG_WARN_NAMED(
802 "empty wait set received in wait(). This should never happen.");
804 if (this->wait_result_->kind() == WaitResultKind::Ready && current_notify_waitable_) {
805 auto & rcl_wait_set = this->wait_result_->get_wait_set().get_rcl_wait_set();
806 if (current_notify_waitable_->is_ready(rcl_wait_set)) {
807 current_notify_waitable_->execute(current_notify_waitable_->take_data());
816 TRACETOOLS_TRACEPOINT(rclcpp_executor_get_next_ready);
818 bool valid_executable =
false;
820 if (!wait_result_.has_value() || wait_result_->kind() != rclcpp::WaitResultKind::Ready) {
824 if (!valid_executable) {
825 size_t current_timer_index = 0;
827 auto [timer, timer_index] = wait_result_->peek_next_ready_timer(current_timer_index);
828 if (
nullptr == timer) {
831 current_timer_index = timer_index;
832 auto entity_iter = current_collection_.timers.find(timer->get_timer_handle().get());
833 if (entity_iter != current_collection_.timers.end()) {
834 auto callback_group = entity_iter->second.callback_group.lock();
835 if (!callback_group || !callback_group->can_be_taken_from()) {
836 current_timer_index++;
843 wait_result_->clear_timer_with_index(current_timer_index);
845 any_executable.data = timer->call();
846 if (!any_executable.data) {
847 current_timer_index++;
850 any_executable.timer = timer;
851 any_executable.callback_group = callback_group;
852 valid_executable =
true;
855 current_timer_index++;
859 if (!valid_executable) {
860 while (
auto subscription = wait_result_->next_ready_subscription()) {
861 auto entity_iter = current_collection_.subscriptions.find(
862 subscription->get_subscription_handle().get());
863 if (entity_iter != current_collection_.subscriptions.end()) {
864 auto callback_group = entity_iter->second.callback_group.lock();
865 if (!callback_group || !callback_group->can_be_taken_from()) {
868 any_executable.subscription = subscription;
869 any_executable.callback_group = callback_group;
870 valid_executable =
true;
876 if (!valid_executable) {
877 while (
auto service = wait_result_->next_ready_service()) {
878 auto entity_iter = current_collection_.services.find(service->get_service_handle().get());
879 if (entity_iter != current_collection_.services.end()) {
880 auto callback_group = entity_iter->second.callback_group.lock();
881 if (!callback_group || !callback_group->can_be_taken_from()) {
884 any_executable.service = service;
885 any_executable.callback_group = callback_group;
886 valid_executable =
true;
892 if (!valid_executable) {
893 while (
auto client = wait_result_->next_ready_client()) {
894 auto entity_iter = current_collection_.clients.find(client->get_client_handle().get());
895 if (entity_iter != current_collection_.clients.end()) {
896 auto callback_group = entity_iter->second.callback_group.lock();
897 if (!callback_group || !callback_group->can_be_taken_from()) {
900 any_executable.client = client;
901 any_executable.callback_group = callback_group;
902 valid_executable =
true;
908 if (!valid_executable) {
909 while (
auto waitable = wait_result_->next_ready_waitable()) {
910 auto entity_iter = current_collection_.waitables.find(waitable.get());
911 if (entity_iter != current_collection_.waitables.end()) {
912 auto callback_group = entity_iter->second.callback_group.lock();
913 if (!callback_group || !callback_group->can_be_taken_from()) {
916 any_executable.waitable = waitable;
917 any_executable.callback_group = callback_group;
918 any_executable.data = waitable->take_data();
919 valid_executable =
true;
925 if (any_executable.callback_group) {
926 if (any_executable.callback_group->type() == CallbackGroupType::MutuallyExclusive) {
927 assert(any_executable.callback_group->can_be_taken_from().load());
928 any_executable.callback_group->can_be_taken_from().store(
false);
933 return valid_executable;
939 bool success =
false;
Coordinate the order and timing of available communication tasks.
std::shared_ptr< rclcpp::GuardCondition > interrupt_guard_condition_
Guard condition for signaling the rmw layer to wake up for special events.
virtual RCLCPP_PUBLIC void spin_node_some(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr &node)
Add a node, complete all immediately available work, and remove the node.
virtual RCLCPP_PUBLIC void spin_node_all(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr &node, std::chrono::nanoseconds max_duration)
Add a node, complete all immediately available work exhaustively, and remove the node.
virtual RCLCPP_PUBLIC ~Executor()
Default destructor.
virtual RCLCPP_PUBLIC std::vector< rclcpp::CallbackGroup::WeakPtr > get_manually_added_callback_groups()
Get callback groups that belong to executor.
RCLCPP_PUBLIC void wait_for_work(std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
Block until more work becomes avilable or timeout is reached.
RCLCPP_PUBLIC void spin_node_once_nanoseconds(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr &node, std::chrono::nanoseconds timeout)
Add a node to executor, execute the next available unit of work, and remove the node.
RCLCPP_PUBLIC Executor(const rclcpp::ExecutorOptions &options=rclcpp::ExecutorOptions())
Default constructor.
RCLCPP_PUBLIC bool get_next_executable(AnyExecutable &any_executable, std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
Wait for executable in ready state and populate union structure.
virtual RCLCPP_PUBLIC void spin_once(std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
Collect work once and execute the next available work, optionally within a duration.
virtual RCLCPP_PUBLIC void spin_some(std::chrono::nanoseconds max_duration=std::chrono::nanoseconds(0))
Collect work once and execute all available work, optionally within a max duration.
virtual RCLCPP_PUBLIC void cancel()
Cancel any running spin* function, causing it to return.
static RCLCPP_PUBLIC void execute_timer(const rclcpp::TimerBase::SharedPtr &timer, const std::shared_ptr< void > &data_ptr)
Run timer executable.
RCLCPP_PUBLIC bool is_spinning()
Returns true if the executor is currently spinning.
virtual RCLCPP_PUBLIC void handle_updated_entities(bool notify)
This function triggers a recollect of all entities that are registered to the executor.
RCLCPP_PUBLIC bool get_next_ready_executable(AnyExecutable &any_executable)
Check for executable in ready state and populate union structure.
std::shared_ptr< rclcpp::Context > context_
The context associated with this executor.
virtual RCLCPP_PUBLIC void remove_node(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr &node_ptr, bool notify=true)
Remove a node from the executor.
RCLCPP_PUBLIC void collect_entities()
Gather all of the waitable entities from associated nodes and callback groups.
virtual RCLCPP_PUBLIC std::vector< rclcpp::CallbackGroup::WeakPtr > get_automatically_added_callback_groups_from_nodes()
Get callback groups that belong to executor.
virtual RCLCPP_PUBLIC FutureReturnCode spin_until_future_complete_impl(std::chrono::nanoseconds timeout, const std::function< std::future_status(std::chrono::nanoseconds wait_time)> &wait_for_future)
Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
virtual RCLCPP_PUBLIC void remove_callback_group(const rclcpp::CallbackGroup::SharedPtr &group_ptr, bool notify=true)
Remove a callback group from the executor.
static RCLCPP_PUBLIC void execute_client(const rclcpp::ClientBase::SharedPtr &client)
Run service client executable.
rclcpp::OnShutdownCallbackHandle shutdown_callback_handle_
shutdown callback handle registered to Context
static RCLCPP_PUBLIC void execute_service(const rclcpp::ServiceBase::SharedPtr &service)
Run service server executable.
RCLCPP_PUBLIC void execute_any_executable(AnyExecutable &any_exec)
Find the next available executable and do the work associated with it.
std::shared_ptr< rclcpp::executors::ExecutorNotifyWaitable > notify_waitable_
Waitable containing guard conditions controlling the executor flow.
virtual RCLCPP_PUBLIC std::vector< rclcpp::CallbackGroup::WeakPtr > get_all_callback_groups()
Get callback groups that belong to executor.
virtual RCLCPP_PUBLIC void add_callback_group(const rclcpp::CallbackGroup::SharedPtr &group_ptr, const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr &node_ptr, bool notify=true)
Add a callback group to an executor.
virtual RCLCPP_PUBLIC void add_node(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr &node_ptr, bool notify=true)
Add a node to the executor.
std::atomic_bool cancel_requested_
Tracks a pending cancel request that has not yet been consumed by a spin.
rclcpp::executors::ExecutorEntitiesCollector collector_
Collector used to associate executable entities from nodes and guard conditions.
virtual RCLCPP_PUBLIC void spin_all(std::chrono::nanoseconds max_duration)
Collect and execute work repeatedly within a duration or until no more work is available.
RCLCPP_PUBLIC void spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
Collect work and execute available work, optionally within a duration.
static RCLCPP_PUBLIC void execute_subscription(const rclcpp::SubscriptionBase::SharedPtr &subscription)
Run subscription executable.
std::shared_ptr< rclcpp::GuardCondition > shutdown_guard_condition_
Guard condition for signaling the rmw layer to wake up for system shutdown.
std::atomic_bool spinning
Spinning state, used to prevent multi threaded calls to spin.
A condition that can be waited on in a single wait set and asynchronously triggered.
Additional meta data about messages taken from subscriptions.
const rmw_message_info_t & get_rmw_message_info() const
Return the message info as the underlying rmw message info type.
Options used to determine what parts of a subscription get added to or removed from a wait set.
Created when the return code does not match one of the other specialized exceptions.
void update(const EntityCollection< EntityKeyType, EntityValueType > &other, std::function< void(const EntitySharedPtr &)> on_added, std::function< void(const EntitySharedPtr &)> on_removed)
Update this collection based on the contents of another collection.
RCLCPP_PUBLIC void add_node(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr &node_ptr)
Add a node to the entity collector.
RCLCPP_PUBLIC void update_collections()
Update the underlying collections.
RCLCPP_PUBLIC std::vector< rclcpp::CallbackGroup::WeakPtr > get_all_callback_groups() const
Get all callback groups known to this entity collector.
RCLCPP_PUBLIC void add_callback_group(const rclcpp::CallbackGroup::SharedPtr &group_ptr)
Add a callback group to the entity collector.
RCLCPP_PUBLIC void remove_callback_group(const rclcpp::CallbackGroup::SharedPtr &group_ptr)
Remove a callback group from the entity collector.
RCLCPP_PUBLIC std::vector< rclcpp::CallbackGroup::WeakPtr > get_automatically_added_callback_groups() const
Get automatically-added callback groups known to this entity collector.
RCLCPP_PUBLIC void remove_node(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr &node_ptr)
Remove a node from the entity collector.
RCLCPP_PUBLIC std::vector< rclcpp::CallbackGroup::WeakPtr > get_manually_added_callback_groups() const
Get manually-added callback groups known to this entity collector.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC bool ok(const rclcpp::Context::SharedPtr &context=rclcpp::contexts::get_global_default_context())
Check rclcpp's status.
FutureReturnCode
Return codes to be used with spin_until_future_complete.
RCLCPP_PUBLIC Logger get_logger(const std::string &name)
Return a named logger.
Options to be passed to the executor constructor.
Represent the total set of entities for a single executor.
TimerCollection timers
Collection of timers currently in use by the executor.
GuardConditionCollection guard_conditions
Collection of guard conditions currently in use by the executor.
ServiceCollection services
Collection of services currently in use by the executor.
SubscriptionCollection subscriptions
Collection of subscriptions currently in use by the executor.
WaitableCollection waitables
Collection of waitables currently in use by the executor.
ClientCollection clients
Collection of clients currently in use by the executor.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_return_loaned_message_from_subscription(const rcl_subscription_t *subscription, void *loaned_message)
Return a loaned message from a topic using a rcl subscription.
#define RCL_RET_OK
Success return code.
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.