15 #include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
21 #include "rcpputils/compile_warnings.hpp"
22 #include "rcpputils/scope_exit.hpp"
24 using namespace std::chrono_literals;
27 RCPPUTILS_DEPRECATION_WARNING_OFF_START
31 EventsExecutor::EventsExecutor(
33 rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue,
34 bool execute_timers_separate_thread)
39 throw std::invalid_argument(
"events_queue can't be a null pointer");
41 events_queue_ = std::move(events_queue);
48 const std::shared_ptr<void> &)> timer_on_ready_cb =
nullptr;
49 if (!execute_timers_separate_thread) {
52 ExecutorEvent event = {timer_id, data, -1, ExecutorEventType::TIMER_EVENT, 1};
53 this->events_queue_->enqueue(event);
57 std::make_shared<rclcpp::experimental::TimersManager>(
context_, timer_on_ready_cb);
59 entities_need_rebuild_ =
false;
61 this->setup_notify_waitable();
65 this->current_collection_.clear();
69 this->add_notify_waitable_to_collection(current_collection_.waitables);
73 EventsExecutor::setup_notify_waitable()
77 assert(
notify_waitable_ &&
"The notify waitable should have already been constructed");
91 [
this, notify_waitable_entity_id](
size_t num_events,
int waitable_data) {
98 if (entities_need_rebuild_.exchange(
true)) {
102 ExecutorEvent
event =
103 {notify_waitable_entity_id,
nullptr, waitable_data, ExecutorEventType::WAITABLE_EVENT, 1};
104 this->events_queue_->enqueue(event);
112 this->refresh_current_collection({});
119 throw std::runtime_error(
"spin() called while already spinning");
121 RCPPUTILS_SCOPE_EXIT(
123 this->cancel_requested_.store(
false););
128 timers_manager_->start();
129 RCPPUTILS_SCOPE_EXIT(timers_manager_->stop(); );
134 bool has_event = events_queue_->dequeue(event);
136 this->execute_event(event);
150 if (max_duration <= 0ns) {
151 throw std::invalid_argument(
"max_duration must be positive");
160 throw std::runtime_error(
"spin_some() called while already spinning");
163 RCPPUTILS_SCOPE_EXIT(
165 this->cancel_requested_.store(
false););
170 auto start = std::chrono::steady_clock::now();
172 auto max_duration_not_elapsed = [max_duration, start]() {
173 if (std::chrono::nanoseconds(0) == max_duration) {
176 }
else if (std::chrono::steady_clock::now() - start < max_duration) {
193 const size_t ready_events_at_start = events_queue_->size();
194 size_t executed_events = 0;
195 const size_t ready_timers_at_start = timers_manager_->get_number_ready_timers();
196 size_t executed_timers = 0;
200 if (exhaustive || (executed_events < ready_events_at_start)) {
201 bool has_event = !events_queue_->empty();
205 bool ret = events_queue_->dequeue(event, std::chrono::nanoseconds(0));
207 this->execute_event(event);
215 if (exhaustive || (executed_timers < ready_timers_at_start)) {
216 bool timer_executed = timers_manager_->execute_head_timer();
217 if (timer_executed) {
233 timeout = std::chrono::nanoseconds::max();
238 bool is_timer_timeout =
false;
239 auto next_timer_timeout = timers_manager_->get_head_timeout();
240 if (next_timer_timeout.has_value() && next_timer_timeout.value() < timeout) {
241 timeout = next_timer_timeout.value();
242 is_timer_timeout =
true;
246 bool has_event = events_queue_->dequeue(event, timeout);
251 this->execute_event(event);
252 }
else if (is_timer_timeout) {
253 timers_manager_->execute_head_timer();
261 switch (event.type) {
262 case ExecutorEventType::CLIENT_EVENT:
264 rclcpp::ClientBase::SharedPtr client;
266 client = this->retrieve_entity(
268 current_collection_.clients);
271 for (
size_t i = 0; i <
event.num_events; i++) {
278 case ExecutorEventType::SUBSCRIPTION_EVENT:
280 rclcpp::SubscriptionBase::SharedPtr subscription;
282 subscription = this->retrieve_entity(
284 current_collection_.subscriptions);
287 for (
size_t i = 0; i <
event.num_events; i++) {
293 case ExecutorEventType::SERVICE_EVENT:
295 rclcpp::ServiceBase::SharedPtr service;
297 service = this->retrieve_entity(
299 current_collection_.services);
302 for (
size_t i = 0; i <
event.num_events; i++) {
309 case ExecutorEventType::TIMER_EVENT:
311 timers_manager_->execute_ready_timer(
315 case ExecutorEventType::WAITABLE_EVENT:
317 rclcpp::Waitable::SharedPtr waitable;
319 waitable = this->retrieve_entity(
321 current_collection_.waitables);
324 for (
size_t i = 0; i <
event.num_events; i++) {
325 const auto data = waitable->take_data_by_entity_id(event.waitable_data);
326 waitable->execute(data);
342 const bool notify_waitable_triggered = entities_need_rebuild_.exchange(
false);
351 rclcpp::executors::build_entities_collection(callback_groups, new_collection);
362 this->add_notify_waitable_to_collection(new_collection.
waitables);
364 this->refresh_current_collection(new_collection);
368 EventsExecutor::refresh_current_collection(
372 std::lock_guard<std::mutex> guard(mutex_);
377 current_collection_.remove_expired_entities();
379 current_collection_.timers.update(
381 [
this](rclcpp::TimerBase::SharedPtr timer) {timers_manager_->add_timer(timer);},
382 [
this](rclcpp::TimerBase::SharedPtr timer) {timers_manager_->remove_timer(timer);});
384 current_collection_.subscriptions.update(
386 [
this](
auto subscription) {
387 subscription->set_on_new_message_callback(
388 this->create_entity_callback(
389 subscription->get_subscription_handle().get(), ExecutorEventType::SUBSCRIPTION_EVENT));
391 [](
auto subscription) {subscription->clear_on_new_message_callback();});
393 current_collection_.clients.update(
395 [
this](
auto client) {
396 client->set_on_new_response_callback(
397 this->create_entity_callback(
398 client->get_client_handle().get(), ExecutorEventType::CLIENT_EVENT));
400 [](
auto client) {client->clear_on_new_response_callback();});
402 current_collection_.services.update(
404 [
this](
auto service) {
405 service->set_on_new_request_callback(
406 this->create_entity_callback(
407 service->get_service_handle().get(), ExecutorEventType::SERVICE_EVENT));
409 [](
auto service) {service->clear_on_new_request_callback();});
418 current_collection_.waitables.update(
420 [
this](
auto waitable) {
421 waitable->set_on_ready_callback(
422 this->create_waitable_callback(waitable.get()));
423 for (const auto & t : waitable->get_timers()) {
424 timers_manager_->add_timer(t);
427 [
this](
auto waitable) {
428 waitable->clear_on_ready_callback();
429 for (
const auto & t : waitable->get_timers()) {
430 timers_manager_->remove_timer(t);
435 std::function<void(
size_t)>
436 EventsExecutor::create_entity_callback(
437 void * entity_key, ExecutorEventType event_type)
439 std::function<void(
size_t)>
440 callback = [
this, entity_key, event_type](
size_t num_events) {
441 ExecutorEvent
event = {entity_key,
nullptr, -1, event_type, num_events};
442 this->events_queue_->enqueue(event);
447 std::function<void(
size_t,
int)>
448 EventsExecutor::create_waitable_callback(
const rclcpp::Waitable * entity_key)
450 std::function<void(
size_t,
int)>
451 callback = [
this, entity_key](
size_t num_events,
int waitable_data) {
452 ExecutorEvent
event =
453 {entity_key,
nullptr, waitable_data, ExecutorEventType::WAITABLE_EVENT, num_events};
454 this->events_queue_->enqueue(event);
460 EventsExecutor::add_notify_waitable_to_collection(
464 rclcpp::CallbackGroup::WeakPtr weak_group_ptr;
467 this->notify_waitable_.get(),
468 {this->notify_waitable_, weak_group_ptr}
472 RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
Coordinate the order and timing of available communication tasks.
std::shared_ptr< rclcpp::Context > context_
The context associated with this executor.
static RCLCPP_PUBLIC void execute_client(const rclcpp::ClientBase::SharedPtr &client)
Run service client executable.
static RCLCPP_PUBLIC void execute_service(const rclcpp::ServiceBase::SharedPtr &service)
Run service server executable.
std::shared_ptr< rclcpp::executors::ExecutorNotifyWaitable > notify_waitable_
Waitable containing guard conditions controlling the executor flow.
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.
static RCLCPP_PUBLIC void execute_subscription(const rclcpp::SubscriptionBase::SharedPtr &subscription)
Run subscription executable.
std::atomic_bool spinning
Spinning state, used to prevent multi threaded calls to spin.
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.
bool has_pending() const
Indicate if the entities collector has pending additions or removals.
Events executor implementation.
RCLCPP_PUBLIC void spin_once_impl(std::chrono::nanoseconds timeout) override
Internal implementation of spin_once.
RCLCPP_PUBLIC void spin() override
Events executor implementation of spin.
virtual RCLCPP_PUBLIC ~EventsExecutor()
Default destructor.
RCLCPP_PUBLIC void spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
Internal implementation of spin_some.
RCLCPP_PUBLIC void spin_all(std::chrono::nanoseconds max_duration) override
Events executor implementation of spin all.
RCLCPP_PUBLIC void handle_updated_entities(bool notify) override
Collect entities from callback groups and refresh the current collection with them.
RCLCPP_PUBLIC void spin_some(std::chrono::nanoseconds max_duration=std::chrono::nanoseconds(0)) override
Events executor implementation of spin some.
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.
Structure which encapsulates a ROS Client.
Structure which encapsulates a ROS Service.
Structure which encapsulates a ROS Subscription.
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.
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.