15 #include "rclcpp/executors/executor_entities_collection.hpp"
16 #include "rcpputils/scope_exit.hpp"
18 #include "rclcpp/executors/static_single_threaded_executor.hpp"
19 #include "rclcpp/any_executable.hpp"
34 throw std::runtime_error(
"spin() called while already spinning");
36 RCPPUTILS_SCOPE_EXIT(this->
spinning.store(
false); );
42 this->spin_once_impl(std::chrono::nanoseconds(-1));
50 if (std::chrono::nanoseconds(0) == max_duration) {
51 max_duration = std::chrono::nanoseconds::max();
53 return this->spin_some_impl(max_duration,
false);
59 if (max_duration < std::chrono::nanoseconds(0)) {
60 throw std::invalid_argument(
"max_duration must be greater than or equal to 0");
62 return this->spin_some_impl(max_duration,
true);
66 StaticSingleThreadedExecutor::spin_some_impl(std::chrono::nanoseconds max_duration,
bool exhaustive)
68 auto start = std::chrono::steady_clock::now();
69 auto max_duration_not_elapsed = [max_duration, start]() {
70 const auto spin_forever = std::chrono::nanoseconds(0) == max_duration;
71 const auto cur_duration = std::chrono::steady_clock::now() - start;
72 return spin_forever || (cur_duration < max_duration);
76 throw std::runtime_error(
"spin_some() called while already spinning");
78 RCPPUTILS_SCOPE_EXIT(this->
spinning.store(
false););
82 std::lock_guard<std::mutex> guard(mutex_);
84 auto wait_result = this->collect_and_wait(std::chrono::nanoseconds(0));
85 if (wait_result.has_value()) {
91 if (!work_available || !exhaustive) {
99 StaticSingleThreadedExecutor::spin_once_impl(std::chrono::nanoseconds timeout)
102 std::lock_guard<std::mutex> guard(mutex_);
103 auto wait_result = this->collect_and_wait(timeout);
104 if (wait_result.has_value()) {
110 std::optional<rclcpp::WaitResult<rclcpp::WaitSet>>
111 StaticSingleThreadedExecutor::collect_and_wait(std::chrono::nanoseconds timeout)
116 std::vector<rclcpp::CallbackGroup::SharedPtr> cbgs;
118 if (this->entities_need_rebuild_.exchange(
false) || current_collection_.empty()) {
123 cbgs.resize(callback_groups.size());
124 for(
const auto & w_ptr : callback_groups) {
125 auto shr_ptr = w_ptr.lock();
127 cbgs.push_back(std::move(shr_ptr));
131 auto wait_result = wait_set_.wait(std::chrono::nanoseconds(timeout));
136 if (wait_result.kind() == WaitResultKind::Empty) {
137 RCUTILS_LOG_WARN_NAMED(
139 "empty wait set received in wait(). This should never happen.");
142 if (wait_result.kind() == WaitResultKind::Ready && current_notify_waitable_) {
143 auto & rcl_wait_set = wait_result.get_wait_set().get_rcl_wait_set();
144 if (current_notify_waitable_->is_ready(rcl_wait_set)) {
145 current_notify_waitable_->execute(current_notify_waitable_->take_data());
159 bool any_ready_executable =
false;
160 if (wait_result.
kind() != rclcpp::WaitResultKind::Ready) {
161 return any_ready_executable;
165 auto entity_iter = collection.
subscriptions.find(subscription->get_subscription_handle().get());
168 any_ready_executable =
true;
169 if (
spin_once) {
return any_ready_executable;}
173 size_t current_timer_index = 0;
176 if (
nullptr == timer) {
179 current_timer_index = timer_index;
180 auto entity_iter = collection.
timers.find(timer->get_timer_handle().get());
181 if (entity_iter != collection.
timers.end()) {
183 auto data = timer->call();
190 any_ready_executable =
true;
191 if (
spin_once) {
return any_ready_executable;}
196 auto entity_iter = collection.
clients.find(client->get_client_handle().get());
197 if (entity_iter != collection.
clients.end()) {
199 any_ready_executable =
true;
200 if (
spin_once) {
return any_ready_executable;}
205 auto entity_iter = collection.
services.find(service->get_service_handle().get());
206 if (entity_iter != collection.
services.end()) {
208 any_ready_executable =
true;
209 if (
spin_once) {
return any_ready_executable;}
214 auto entity_iter = collection.
waitables.find(waitable.get());
215 if (entity_iter != collection.
waitables.end()) {
216 const auto data = waitable->take_data();
217 waitable->execute(data);
218 any_ready_executable =
true;
219 if (
spin_once) {
return any_ready_executable;}
222 return any_ready_executable;
Coordinate the order and timing of available communication tasks.
static RCLCPP_PUBLIC void execute_service(rclcpp::ServiceBase::SharedPtr service)
Run service server executable.
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.
std::shared_ptr< rclcpp::Context > context_
The context associated with this executor.
static RCLCPP_PUBLIC void execute_timer(rclcpp::TimerBase::SharedPtr timer, const std::shared_ptr< void > &data_ptr)
Run timer executable.
static RCLCPP_PUBLIC void execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
Run subscription executable.
RCLCPP_PUBLIC void collect_entities()
Gather all of the waitable entities from associated nodes and callback groups.
static RCLCPP_PUBLIC void execute_client(rclcpp::ClientBase::SharedPtr client)
Run service client executable.
rclcpp::executors::ExecutorEntitiesCollector collector_
Collector used to associate executable entities from nodes and guard conditions.
std::atomic_bool spinning
Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins.
Interface for introspecting a wait set after waiting on it.
std::shared_ptr< rclcpp::SubscriptionBase > next_ready_subscription()
Get the next ready subscription, clearing it from the wait result.
std::pair< std::shared_ptr< rclcpp::TimerBase >, size_t > peek_next_ready_timer(size_t start_index=0)
Get the next ready timer and its index in the wait result, but do not clear it.
std::shared_ptr< rclcpp::ServiceBase > next_ready_service()
Get the next ready service, clearing it from the wait result.
WaitResultKind kind() const
Return the kind of the WaitResult.
void clear_timer_with_index(size_t index)
Clear the timer at the given index.
std::shared_ptr< rclcpp::ClientBase > next_ready_client()
Get the next ready client, clearing it from the wait result.
std::shared_ptr< rclcpp::Waitable > next_ready_waitable()
Get the next ready waitable, clearing it from the wait result.
RCLCPP_PUBLIC std::vector< rclcpp::CallbackGroup::WeakPtr > get_all_callback_groups() const
Get all callback groups known to this entity collector.
Static executor implementation.
RCLCPP_PUBLIC void spin_some(std::chrono::nanoseconds max_duration=std::chrono::nanoseconds(0)) override
Static executor implementation of spin some.
RCLCPP_PUBLIC void spin() override
Static executor implementation of spin.
virtual RCLCPP_PUBLIC ~StaticSingleThreadedExecutor()
Default destructor.
RCLCPP_PUBLIC void spin_all(std::chrono::nanoseconds max_duration) override
Static executor implementation of spin all.
bool execute_ready_executables(const rclcpp::executors::ExecutorEntitiesCollection &collection, rclcpp::WaitResult< rclcpp::WaitSet > &wait_result, bool spin_once)
Executes ready executables from wait set.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC bool ok(rclcpp::Context::SharedPtr context=nullptr)
Check rclcpp's status.
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.