15 #include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
21 #include "rclcpp/utilities.hpp"
22 #include "rcpputils/compile_warnings.hpp"
23 #include "rcpputils/scope_exit.hpp"
25 using namespace std::chrono_literals;
28 RCPPUTILS_DEPRECATION_WARNING_OFF_START
32 EventsExecutor::EventsExecutor(
34 rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue,
35 bool execute_timers_separate_thread)
40 throw std::invalid_argument(
"events_queue can't be a null pointer");
42 events_queue_ = std::move(events_queue);
49 const std::shared_ptr<void> &)> timer_on_ready_cb =
nullptr;
50 if (!execute_timers_separate_thread) {
53 ExecutorEvent event = {timer_id, data, -1, ExecutorEventType::TIMER_EVENT, 1};
54 this->events_queue_->enqueue(event);
58 std::make_shared<rclcpp::experimental::TimersManager>(
context_, timer_on_ready_cb);
60 entities_need_rebuild_ =
false;
62 this->setup_notify_waitable();
66 this->current_collection_.clear();
70 this->add_notify_waitable_to_collection(current_collection_.waitables);
74 EventsExecutor::setup_notify_waitable()
78 assert(
notify_waitable_ &&
"The notify waitable should have already been constructed");
92 [
this, notify_waitable_entity_id](
size_t num_events,
int waitable_data) {
99 if (entities_need_rebuild_.exchange(
true)) {
103 ExecutorEvent
event =
104 {notify_waitable_entity_id,
nullptr, waitable_data, ExecutorEventType::WAITABLE_EVENT, 1};
105 this->events_queue_->enqueue(event);
113 this->refresh_current_collection({});
120 throw std::runtime_error(
"spin() called while already spinning");
122 RCPPUTILS_SCOPE_EXIT(
124 this->cancel_requested_.store(
false););
129 timers_manager_->start();
130 RCPPUTILS_SCOPE_EXIT(timers_manager_->stop(); );
135 bool has_event = events_queue_->dequeue(event);
137 this->execute_event(event);
151 if (max_duration <= 0ns) {
152 throw std::invalid_argument(
"max_duration must be positive");
161 throw std::runtime_error(
"spin_some() called while already spinning");
164 RCPPUTILS_SCOPE_EXIT(
166 this->cancel_requested_.store(
false););
171 auto start = std::chrono::steady_clock::now();
173 auto max_duration_not_elapsed = [max_duration, start]() {
174 if (std::chrono::nanoseconds(0) == max_duration) {
177 }
else if (std::chrono::steady_clock::now() - start < max_duration) {
194 const size_t ready_events_at_start = events_queue_->size();
195 size_t executed_events = 0;
196 const size_t ready_timers_at_start = timers_manager_->get_number_ready_timers();
197 size_t executed_timers = 0;
201 if (exhaustive || (executed_events < ready_events_at_start)) {
202 bool has_event = !events_queue_->empty();
206 bool ret = events_queue_->dequeue(event, std::chrono::nanoseconds(0));
208 this->execute_event(event);
216 if (exhaustive || (executed_timers < ready_timers_at_start)) {
217 bool timer_executed = timers_manager_->execute_head_timer();
218 if (timer_executed) {
234 timeout = std::chrono::nanoseconds::max();
239 bool is_timer_timeout =
false;
240 auto next_timer_timeout = timers_manager_->get_head_timeout();
241 if (next_timer_timeout.has_value() && next_timer_timeout.value() < timeout) {
242 timeout = next_timer_timeout.value();
243 is_timer_timeout =
true;
247 bool has_event = events_queue_->dequeue(event, timeout);
252 this->execute_event(event);
253 }
else if (is_timer_timeout) {
254 timers_manager_->execute_head_timer();
262 switch (event.type) {
263 case ExecutorEventType::CLIENT_EVENT:
265 rclcpp::ClientBase::SharedPtr client;
267 client = this->retrieve_entity(
269 current_collection_.clients);
272 for (
size_t i = 0; i <
event.num_events; i++) {
279 case ExecutorEventType::SUBSCRIPTION_EVENT:
281 rclcpp::SubscriptionBase::SharedPtr subscription;
283 subscription = this->retrieve_entity(
285 current_collection_.subscriptions);
288 for (
size_t i = 0; i <
event.num_events; i++) {
294 case ExecutorEventType::SERVICE_EVENT:
296 rclcpp::ServiceBase::SharedPtr service;
298 service = this->retrieve_entity(
300 current_collection_.services);
303 for (
size_t i = 0; i <
event.num_events; i++) {
310 case ExecutorEventType::TIMER_EVENT:
312 timers_manager_->execute_ready_timer(
316 case ExecutorEventType::WAITABLE_EVENT:
318 rclcpp::Waitable::SharedPtr waitable;
320 waitable = this->retrieve_entity(
322 current_collection_.waitables);
325 for (
size_t i = 0; i <
event.num_events; i++) {
326 const auto data = waitable->take_data_by_entity_id(event.waitable_data);
327 waitable->execute(data);
343 const bool notify_waitable_triggered = entities_need_rebuild_.exchange(
false);
352 rclcpp::executors::build_entities_collection(callback_groups, new_collection);
363 this->add_notify_waitable_to_collection(new_collection.
waitables);
365 this->refresh_current_collection(new_collection);
369 EventsExecutor::refresh_current_collection(
373 std::lock_guard<std::mutex> guard(mutex_);
378 current_collection_.remove_expired_entities();
380 current_collection_.timers.update(
382 [
this](rclcpp::TimerBase::SharedPtr timer) {timers_manager_->add_timer(timer);},
383 [
this](rclcpp::TimerBase::SharedPtr timer) {timers_manager_->remove_timer(timer);});
385 current_collection_.subscriptions.update(
387 [
this](
auto subscription) {
388 subscription->set_on_new_message_callback(
389 this->create_entity_callback(
390 subscription->get_subscription_handle().get(), ExecutorEventType::SUBSCRIPTION_EVENT));
392 [](
auto subscription) {subscription->clear_on_new_message_callback();});
394 current_collection_.clients.update(
396 [
this](
auto client) {
397 client->set_on_new_response_callback(
398 this->create_entity_callback(
399 client->get_client_handle().get(), ExecutorEventType::CLIENT_EVENT));
401 [](
auto client) {client->clear_on_new_response_callback();});
403 current_collection_.services.update(
405 [
this](
auto service) {
406 service->set_on_new_request_callback(
407 this->create_entity_callback(
408 service->get_service_handle().get(), ExecutorEventType::SERVICE_EVENT));
410 [](
auto service) {service->clear_on_new_request_callback();});
419 current_collection_.waitables.update(
421 [
this](
auto waitable) {
422 waitable->set_on_ready_callback(
423 this->create_waitable_callback(waitable.get()));
424 for (const auto & t : waitable->get_timers()) {
425 timers_manager_->add_timer(t);
428 [
this](
auto waitable) {
429 waitable->clear_on_ready_callback();
430 for (
const auto & t : waitable->get_timers()) {
431 timers_manager_->remove_timer(t);
436 std::function<void(
size_t)>
437 EventsExecutor::create_entity_callback(
438 void * entity_key, ExecutorEventType event_type)
440 std::function<void(
size_t)>
441 callback = [
this, entity_key, event_type](
size_t num_events) {
442 ExecutorEvent
event = {entity_key,
nullptr, -1, event_type, num_events};
443 this->events_queue_->enqueue(event);
448 std::function<void(
size_t,
int)>
449 EventsExecutor::create_waitable_callback(
const rclcpp::Waitable * entity_key)
451 std::function<void(
size_t,
int)>
452 callback = [
this, entity_key](
size_t num_events,
int waitable_data) {
453 ExecutorEvent
event =
454 {entity_key,
nullptr, waitable_data, ExecutorEventType::WAITABLE_EVENT, num_events};
455 this->events_queue_->enqueue(event);
461 EventsExecutor::add_notify_waitable_to_collection(
465 rclcpp::CallbackGroup::WeakPtr weak_group_ptr;
468 this->notify_waitable_.get(),
469 {this->notify_waitable_, weak_group_ptr}
473 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.