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)
57 entities_need_rebuild_(true),
59 wait_set_({}, {}, {}, {}, {}, {}, context)
67 context_(options.context),
68 notify_waitable_(std::make_shared<
rclcpp::executors::ExecutorNotifyWaitable>(
70 this->entities_need_rebuild_.store(
true);
72 entities_need_rebuild_(
true),
73 collector_(notify_waitable_),
74 wait_set_({}, {}, {}, {}, {}, {}, options.context),
75 current_notify_waitable_(notify_waitable_),
76 impl_(std::make_unique<rclcpp::ExecutorImplementation>())
78 shutdown_callback_handle_ = context_->add_on_shutdown_callback(
79 [weak_gc = std::weak_ptr<rclcpp::GuardCondition>{shutdown_guard_condition_}]() {
80 auto strong_gc = weak_gc.lock();
86 notify_waitable_->add_guard_condition(interrupt_guard_condition_);
87 notify_waitable_->add_guard_condition(shutdown_guard_condition_);
96 std::lock_guard<std::mutex> guard(mutex_);
100 current_collection_.timers.update(
102 [
this](
auto timer) {wait_set_.remove_timer(std::move(timer));});
104 current_collection_.subscriptions.update(
106 [
this](
auto subscription) {
107 wait_set_.remove_subscription(std::move(subscription), kDefaultSubscriptionMask);
110 current_collection_.clients.update(
112 [
this](
auto client) {wait_set_.remove_client(std::move(client));});
114 current_collection_.services.update(
116 [
this](
auto service) {wait_set_.remove_service(std::move(service));});
118 current_collection_.guard_conditions.update(
120 [
this](
auto guard_condition) {wait_set_.remove_guard_condition(std::move(guard_condition));});
122 current_collection_.waitables.update(
124 [
this](
auto waitable) {wait_set_.remove_waitable(std::move(waitable));});
128 RCUTILS_LOG_ERROR_NAMED(
130 "failed to remove registered on_shutdown callback");
138 this->entities_need_rebuild_.store(
true);
140 if (!
spinning.load() && entities_need_rebuild_.exchange(
false)) {
141 std::lock_guard<std::mutex> guard(mutex_);
150 std::vector<rclcpp::CallbackGroup::WeakPtr>
157 std::vector<rclcpp::CallbackGroup::WeakPtr>
164 std::vector<rclcpp::CallbackGroup::WeakPtr>
173 const rclcpp::CallbackGroup::SharedPtr & group_ptr,
174 [[maybe_unused]]
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
182 throw std::runtime_error(
184 "Failed to handle entities update on callback group add: ") + ex.what());
190 const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
193 if (node_ptr->get_context() !=
context_) {
194 throw std::runtime_error(
195 "add_node() called with a node with a different context from this executor");
203 throw std::runtime_error(
205 "Failed to handle entities update on node add: ") + ex.what());
211 const rclcpp::CallbackGroup::SharedPtr & group_ptr,
219 throw std::runtime_error(
221 "Failed to handle entities update on callback group remove: ") + ex.what());
228 this->
add_node(node_ptr->get_node_base_interface(), notify);
233 const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
241 throw std::runtime_error(
243 "Failed to handle entities update on node remove: ") + ex.what());
250 this->
remove_node(node_ptr->get_node_base_interface(), notify);
255 const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node,
256 std::chrono::nanoseconds timeout)
266 std::chrono::nanoseconds timeout,
267 const std::function<std::future_status(std::chrono::nanoseconds wait_time)> & wait_for_future)
274 std::future_status status = wait_for_future(std::chrono::seconds(0));
275 if (status == std::future_status::ready) {
276 return FutureReturnCode::SUCCESS;
279 auto end_time = std::chrono::steady_clock::now();
280 std::chrono::nanoseconds timeout_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
282 if (timeout_ns > std::chrono::nanoseconds::zero()) {
283 end_time += timeout_ns;
285 std::chrono::nanoseconds timeout_left = timeout_ns;
288 throw std::runtime_error(
"spin_until_future_complete() called while already spinning");
290 RCPPUTILS_SCOPE_EXIT(wait_result_.reset();this->spinning.store(
false););
293 spin_once_impl(timeout_left);
296 status = wait_for_future(std::chrono::seconds(0));
297 if (status == std::future_status::ready) {
298 return FutureReturnCode::SUCCESS;
301 if (timeout_ns < std::chrono::nanoseconds::zero()) {
305 auto now = std::chrono::steady_clock::now();
306 if (now >= end_time) {
307 return FutureReturnCode::TIMEOUT;
310 timeout_left = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - now);
314 return FutureReturnCode::INTERRUPTED;
338 const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node,
339 std::chrono::nanoseconds max_duration)
348 const std::shared_ptr<rclcpp::Node> & node,
349 std::chrono::nanoseconds max_duration)
351 this->
spin_node_all(node->get_node_base_interface(), max_duration);
356 if (max_duration < 0ns) {
357 throw std::invalid_argument(
"max_duration must be greater than or equal to 0");
365 auto start = std::chrono::steady_clock::now();
366 auto max_duration_not_elapsed = [max_duration, start]() {
367 if (std::chrono::nanoseconds(0) == max_duration) {
370 }
else if (std::chrono::steady_clock::now() - start < max_duration) {
379 throw std::runtime_error(
"spin_some() called while already spinning");
381 RCPPUTILS_SCOPE_EXIT(wait_result_.reset();this->spinning.store(
false););
386 wait_result_.reset();
388 bool entity_states_fully_polled =
true;
390 if (entities_need_rebuild_) {
394 entity_states_fully_polled =
false;
419 entity_states_fully_polled =
false;
422 wait_result_.reset();
424 if (entity_states_fully_polled) {
434 entity_states_fully_polled =
true;
435 if (entities_need_rebuild_) {
439 entity_states_fully_polled =
false;
449 Executor::spin_once_impl(std::chrono::nanoseconds timeout)
461 throw std::runtime_error(
"spin_once() called while already spinning");
463 RCPPUTILS_SCOPE_EXIT(wait_result_.reset();this->spinning.store(
false););
464 spin_once_impl(timeout);
474 throw std::runtime_error(
475 std::string(
"Failed to trigger guard condition in cancel: ") + ex.what());
487 (
void(
"cannot execute an AnyExecutable without a valid callback group"),
488 any_exec.callback_group));
490 if (any_exec.timer) {
491 TRACETOOLS_TRACEPOINT(
492 rclcpp_executor_execute,
493 static_cast<const void *
>(any_exec.timer->get_timer_handle().get()));
496 if (any_exec.subscription) {
497 TRACETOOLS_TRACEPOINT(
498 rclcpp_executor_execute,
499 static_cast<const void *
>(any_exec.subscription->get_subscription_handle().get()));
502 if (any_exec.service) {
505 if (any_exec.client) {
508 if (any_exec.waitable) {
509 const std::shared_ptr<void> & const_data = any_exec.data;
510 any_exec.waitable->execute(const_data);
514 any_exec.callback_group->can_be_taken_from().store(
true);
517 template<
typename Taker,
typename Handler>
520 take_and_do_error_handling(
521 const char * action_description,
522 const char * topic_or_service_name,
524 Handler handle_action)
528 taken = take_action();
532 "executor %s '%s' unexpectedly failed: %s",
534 topic_or_service_name,
548 "executor %s '%s' failed to take anything",
550 topic_or_service_name);
562 switch (subscription->get_delivered_message_kind()) {
564 case rclcpp::DeliveredMessageKind::ROS_MESSAGE:
566 if (subscription->can_loan_messages()) {
570 void * loaned_msg =
nullptr;
573 take_and_do_error_handling(
574 "taking a loaned message from topic",
575 subscription->get_topic_name(),
578 rcl_ret_t ret = rcl_take_loaned_message(
579 subscription->get_subscription_handle().get(),
581 &message_info.get_rmw_message_info(),
583 TRACETOOLS_TRACEPOINT(rclcpp_take, static_cast<const void *>(loaned_msg));
584 if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
587 rclcpp::exceptions::throw_from_rcl_error(ret);
591 [&]() {subscription->handle_loaned_message(loaned_msg, message_info);});
592 if (
nullptr != loaned_msg) {
594 subscription->get_subscription_handle().get(), loaned_msg);
598 "rcl_return_loaned_message_from_subscription() failed for subscription on topic "
600 subscription->get_topic_name(), rcl_get_error_string().str);
603 loaned_msg =
nullptr;
608 std::shared_ptr<void> message = subscription->create_message();
609 take_and_do_error_handling(
610 "taking a message from topic",
611 subscription->get_topic_name(),
612 [&]() {return subscription->take_type_erased(message.get(), message_info);},
613 [&]() {subscription->handle_message(message, message_info);});
619 subscription->return_message(message);
625 case rclcpp::DeliveredMessageKind::SERIALIZED_MESSAGE:
629 std::shared_ptr<SerializedMessage> serialized_msg =
630 subscription->create_serialized_message();
631 take_and_do_error_handling(
632 "taking a serialized message from topic",
633 subscription->get_topic_name(),
634 [&]() {return subscription->take_serialized(*serialized_msg.get(), message_info);},
637 subscription->handle_serialized_message(serialized_msg, message_info);
639 subscription->return_serialized_message(serialized_msg);
645 case rclcpp::DeliveredMessageKind::DYNAMIC_MESSAGE:
647 throw std::runtime_error(
"Unimplemented");
650 case rclcpp::DeliveredMessageKind::INVALID:
652 throw std::runtime_error(
"Delivered message kind is not supported");
658 Executor::execute_timer(
659 const rclcpp::TimerBase::SharedPtr & timer,
660 const std::shared_ptr<void> & data_ptr)
662 timer->execute_callback(data_ptr);
668 auto request_header = service->create_request_header();
669 std::shared_ptr<void> request = service->create_request();
670 take_and_do_error_handling(
671 "taking a service server request from service",
672 service->get_service_name(),
673 [&]() {return service->take_type_erased_request(request.get(), *request_header);},
674 [&]() {service->handle_request(request_header, request);});
680 auto request_header = client->create_request_header();
681 std::shared_ptr<void> response = client->create_response();
682 take_and_do_error_handling(
683 "taking a service client response from service",
684 client->get_service_name(),
685 [&]() {return client->take_type_erased_response(response.get(), *request_header);},
686 [&]() {client->handle_response(request_header, response);});
693 this->wait_result_.reset();
699 rclcpp::executors::build_entities_collection(callback_groups, collection);
706 current_notify_waitable_ = std::make_shared<rclcpp::executors::ExecutorNotifyWaitable>(
708 auto notify_waitable = std::static_pointer_cast<rclcpp::Waitable>(current_notify_waitable_);
709 collection.
waitables.insert({notify_waitable.get(), {notify_waitable, {}}});
714 current_collection_.remove_expired_entities();
718 current_collection_.timers.
update(
720 [
this](
auto timer) {wait_set_.add_timer(std::move(timer));},
721 [
this](
auto timer) {wait_set_.remove_timer(std::move(timer));});
723 current_collection_.subscriptions.update(
725 [
this](
auto subscription) {
726 wait_set_.add_subscription(std::move(subscription), kDefaultSubscriptionMask);
728 [
this](
auto subscription) {
729 wait_set_.remove_subscription(std::move(subscription), kDefaultSubscriptionMask);
732 current_collection_.clients.update(
734 [
this](
auto client) {wait_set_.add_client(std::move(client));},
735 [
this](
auto client) {wait_set_.remove_client(std::move(client));});
737 current_collection_.services.update(
739 [
this](
auto service) {wait_set_.add_service(std::move(service));},
740 [
this](
auto service) {wait_set_.remove_service(std::move(service));});
742 current_collection_.guard_conditions.update(
744 [
this](
auto guard_condition) {wait_set_.add_guard_condition(std::move(guard_condition));},
745 [
this](
auto guard_condition) {wait_set_.remove_guard_condition(std::move(guard_condition));});
747 current_collection_.waitables.update(
749 [
this](
auto waitable) {wait_set_.add_waitable(std::move(waitable));},
750 [
this](
auto waitable) {wait_set_.remove_waitable(std::move(waitable));});
754 this->wait_set_.prune_deleted_entities();
760 TRACETOOLS_TRACEPOINT(rclcpp_executor_wait_for_work, timeout.count());
763 this->wait_result_.reset();
766 std::lock_guard<std::mutex> guard(mutex_);
768 if (this->entities_need_rebuild_.exchange(
false) || current_collection_.empty()) {
773 this->wait_result_.emplace(wait_set_.wait(timeout));
775 if (!this->wait_result_ || this->wait_result_->kind() == WaitResultKind::Empty) {
776 RCUTILS_LOG_WARN_NAMED(
778 "empty wait set received in wait(). This should never happen.");
780 if (this->wait_result_->kind() == WaitResultKind::Ready && current_notify_waitable_) {
781 auto & rcl_wait_set = this->wait_result_->get_wait_set().get_rcl_wait_set();
782 if (current_notify_waitable_->is_ready(rcl_wait_set)) {
783 current_notify_waitable_->execute(current_notify_waitable_->take_data());
792 TRACETOOLS_TRACEPOINT(rclcpp_executor_get_next_ready);
794 bool valid_executable =
false;
796 if (!wait_result_.has_value() || wait_result_->kind() != rclcpp::WaitResultKind::Ready) {
800 if (!valid_executable) {
801 size_t current_timer_index = 0;
803 auto [timer, timer_index] = wait_result_->peek_next_ready_timer(current_timer_index);
804 if (
nullptr == timer) {
807 current_timer_index = timer_index;
808 auto entity_iter = current_collection_.timers.find(timer->get_timer_handle().get());
809 if (entity_iter != current_collection_.timers.end()) {
810 auto callback_group = entity_iter->second.callback_group.lock();
811 if (!callback_group || !callback_group->can_be_taken_from()) {
812 current_timer_index++;
819 wait_result_->clear_timer_with_index(current_timer_index);
821 any_executable.data = timer->call();
822 if (!any_executable.data) {
823 current_timer_index++;
826 any_executable.timer = timer;
827 any_executable.callback_group = callback_group;
828 valid_executable =
true;
831 current_timer_index++;
835 if (!valid_executable) {
836 while (
auto subscription = wait_result_->next_ready_subscription()) {
837 auto entity_iter = current_collection_.subscriptions.find(
838 subscription->get_subscription_handle().get());
839 if (entity_iter != current_collection_.subscriptions.end()) {
840 auto callback_group = entity_iter->second.callback_group.lock();
841 if (!callback_group || !callback_group->can_be_taken_from()) {
844 any_executable.subscription = subscription;
845 any_executable.callback_group = callback_group;
846 valid_executable =
true;
852 if (!valid_executable) {
853 while (
auto service = wait_result_->next_ready_service()) {
854 auto entity_iter = current_collection_.services.find(service->get_service_handle().get());
855 if (entity_iter != current_collection_.services.end()) {
856 auto callback_group = entity_iter->second.callback_group.lock();
857 if (!callback_group || !callback_group->can_be_taken_from()) {
860 any_executable.service = service;
861 any_executable.callback_group = callback_group;
862 valid_executable =
true;
868 if (!valid_executable) {
869 while (
auto client = wait_result_->next_ready_client()) {
870 auto entity_iter = current_collection_.clients.find(client->get_client_handle().get());
871 if (entity_iter != current_collection_.clients.end()) {
872 auto callback_group = entity_iter->second.callback_group.lock();
873 if (!callback_group || !callback_group->can_be_taken_from()) {
876 any_executable.client = client;
877 any_executable.callback_group = callback_group;
878 valid_executable =
true;
884 if (!valid_executable) {
885 while (
auto waitable = wait_result_->next_ready_waitable()) {
886 auto entity_iter = current_collection_.waitables.find(waitable.get());
887 if (entity_iter != current_collection_.waitables.end()) {
888 auto callback_group = entity_iter->second.callback_group.lock();
889 if (!callback_group || !callback_group->can_be_taken_from()) {
892 any_executable.waitable = waitable;
893 any_executable.callback_group = callback_group;
894 any_executable.data = waitable->take_data();
895 valid_executable =
true;
901 if (any_executable.callback_group) {
902 if (any_executable.callback_group->type() == CallbackGroupType::MutuallyExclusive) {
903 assert(any_executable.callback_group->can_be_taken_from().load());
904 any_executable.callback_group->can_be_taken_from().store(
false);
909 return valid_executable;
915 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.
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 and to cancel blocking spins.
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.