rclcpp  master
C++ ROS Client Library API
executor.hpp
Go to the documentation of this file.
1 // Copyright 2014 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef RCLCPP__EXECUTOR_HPP_
16 #define RCLCPP__EXECUTOR_HPP_
17 
18 #include <algorithm>
19 #include <cassert>
20 #include <chrono>
21 #include <cstdlib>
22 #include <iostream>
23 #include <list>
24 #include <memory>
25 #include <mutex>
26 #include <string>
27 #include <vector>
28 
29 #include "rcl/guard_condition.h"
30 #include "rcl/wait.h"
31 
38 #include "rclcpp/utilities.hpp"
40 #include "rclcpp/scope_exit.hpp"
41 
42 namespace rclcpp
43 {
44 
45 // Forward declaration is used in convenience method signature.
46 class Node;
47 
49 
58 class Executor
59 {
60 public:
62 
63 
64 
68  explicit Executor(const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
69 
72  virtual ~Executor();
73 
75  // It is up to the implementation of Executor to implement spin.
76  virtual void
77  spin() = 0;
78 
80 
88  virtual void
89  add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
90 
92 
96  virtual void
97  add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
98 
100 
107  virtual void
108  remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
109 
111 
115  virtual void
116  remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
117 
119 
125  template<typename RepT = int64_t, typename T = std::milli>
126  void
128  rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
130  {
132  node,
133  std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
134  );
135  }
136 
138  template<typename NodeT = rclcpp::Node, typename RepT = int64_t, typename T = std::milli>
139  void
143  {
145  node->get_node_base_interface(),
146  std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
147  );
148  }
149 
151 
155  void
156  spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node);
157 
160  void
162 
164 
175  virtual void
177 
179  virtual void
181 
183 
192  template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
195  const std::shared_future<ResponseT> & future,
197  {
198  // TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
199  // inside a callback executed by an executor.
200 
201  // Check the future before entering the while loop.
202  // If the future is already complete, don't try to spin.
203  std::future_status status = future.wait_for(std::chrono::seconds(0));
204  if (status == std::future_status::ready) {
206  }
207 
208  auto end_time = std::chrono::steady_clock::now();
209  std::chrono::nanoseconds timeout_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
210  timeout);
211  if (timeout_ns > std::chrono::nanoseconds::zero()) {
212  end_time += timeout_ns;
213  }
214  std::chrono::nanoseconds timeout_left = timeout_ns;
215 
216  if (spinning.exchange(true)) {
217  throw std::runtime_error("spin_until_future_complete() called while already spinning");
218  }
219  RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
220  while (rclcpp::ok(this->context_) && spinning.load()) {
221  // Do one item of work.
222  spin_once_impl(timeout_left);
223 
224  // Check if the future is set, return SUCCESS if it is.
225  status = future.wait_for(std::chrono::seconds(0));
226  if (status == std::future_status::ready) {
228  }
229  // If the original timeout is < 0, then this is blocking, never TIMEOUT.
230  if (timeout_ns < std::chrono::nanoseconds::zero()) {
231  continue;
232  }
233  // Otherwise check if we still have time to wait, return TIMEOUT if not.
234  auto now = std::chrono::steady_clock::now();
235  if (now >= end_time) {
237  }
238  // Subtract the elapsed time from the original timeout.
239  timeout_left = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - now);
240  }
241 
242  // The future did not complete before ok() returned false, return INTERRUPTED.
244  }
245 
247 
252  void
253  cancel();
254 
256 
263  void
264  set_memory_strategy(memory_strategy::MemoryStrategy::SharedPtr memory_strategy);
265 
266 protected:
268  void
270  rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
271  std::chrono::nanoseconds timeout);
272 
274 
280  void
282 
284  static void
286  rclcpp::SubscriptionBase::SharedPtr subscription);
287 
289  static void
290  execute_timer(rclcpp::TimerBase::SharedPtr timer);
291 
293  static void
294  execute_service(rclcpp::ServiceBase::SharedPtr service);
295 
297  static void
298  execute_client(rclcpp::ClientBase::SharedPtr client);
299 
304  void
306 
308  rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
309  get_node_by_group(rclcpp::CallbackGroup::SharedPtr group);
310 
312  rclcpp::CallbackGroup::SharedPtr
313  get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
314 
316  bool
317  get_next_ready_executable(AnyExecutable & any_executable);
318 
320  bool
322  AnyExecutable & any_executable,
324 
326  std::atomic_bool spinning;
327 
329  rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
330 
332  rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
333 
334  // Mutex to protect the subsequent memory_strategy_.
336 
338  memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
339 
342 
344 
345  std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
347 
348 private:
350  void
351  spin_once_impl(std::chrono::nanoseconds timeout);
352 };
353 
354 namespace executor
355 {
356 
357 using Executor [[deprecated("use rclcpp::Executor instead")]] = rclcpp::Executor;
358 
359 } // namespace executor
360 } // namespace rclcpp
361 
362 #endif // RCLCPP__EXECUTOR_HPP_
rclcpp::Executor::spin_some
virtual void spin_some(std::chrono::nanoseconds max_duration=std::chrono::nanoseconds(0))
Complete all available queued work without blocking.
rclcpp::Executor::get_node_by_group
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr get_node_by_group(rclcpp::CallbackGroup::SharedPtr group)
std::shared_future
rclcpp::Executor::spin_node_once_nanoseconds
void spin_node_once_nanoseconds(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node, std::chrono::nanoseconds timeout)
rclcpp::FutureReturnCode
FutureReturnCode
Return codes to be used with spin_until_future_complete.
Definition: future_return_code.hpp:33
scope_exit.hpp
rclcpp::Executor::spin_node_once
void spin_node_once(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node, std::chrono::duration< RepT, T > timeout=std::chrono::duration< RepT, T >(-1))
Add a node to executor, execute the next available unit of work, and remove the node.
Definition: executor.hpp:127
std::shared_ptr
RCLCPP_DISABLE_COPY
#define RCLCPP_DISABLE_COPY(...)
Definition: macros.hpp:26
rclcpp::Executor::interrupt_guard_condition_
rcl_guard_condition_t interrupt_guard_condition_
Guard condition for signaling the rmw layer to wake up for special events.
Definition: executor.hpp:329
rclcpp::Executor::spin_once
virtual void spin_once(std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
rclcpp::Executor::execute_client
static void execute_client(rclcpp::ClientBase::SharedPtr client)
rclcpp::Executor::spin
virtual void spin()=0
Do work periodically as it becomes available to us. Blocking call, may block indefinitely.
rclcpp::Executor::memory_strategy_
memory_strategy::MemoryStrategy::SharedPtr memory_strategy_
The memory strategy: an interface for handling user-defined memory allocation strategies.
Definition: executor.hpp:338
std::chrono::duration
rclcpp::Executor::execute_any_executable
void execute_any_executable(AnyExecutable &any_exec)
Find the next available executable and do the work associated with it.
rclcpp::Executor
Coordinate the order and timing of available communication tasks.
Definition: executor.hpp:58
rclcpp::executor::Executor
rclcpp::Executor Executor
Definition: executor.hpp:357
rclcpp::Executor::memory_strategy_mutex_
std::mutex memory_strategy_mutex_
Definition: executor.hpp:335
std::chrono::nanoseconds::zero
T zero(T... args)
rcl_guard_condition_t
rclcpp::Executor::weak_nodes_
std::list< rclcpp::node_interfaces::NodeBaseInterface::WeakPtr > weak_nodes_
Definition: executor.hpp:345
rclcpp::Executor::cancel
void cancel()
Cancel any running spin* function, causing it to return.
rclcpp::ok
bool ok(rclcpp::Context::SharedPtr context=nullptr)
Check rclcpp's status.
rclcpp
This header provides the get_node_base_interface() template function.
Definition: allocator_common.hpp:24
RCLCPP_PUBLIC
#define RCLCPP_PUBLIC
Definition: visibility_control.hpp:50
rclcpp::Executor::get_group_by_timer
rclcpp::CallbackGroup::SharedPtr get_group_by_timer(rclcpp::TimerBase::SharedPtr timer)
rclcpp::Executor::execute_timer
static void execute_timer(rclcpp::TimerBase::SharedPtr timer)
rclcpp::Executor::execute_service
static void execute_service(rclcpp::ServiceBase::SharedPtr service)
rclcpp::ExecutorOptions
Options to be passed to the executor constructor.
Definition: executor_options.hpp:28
rclcpp::FutureReturnCode::SUCCESS
@ SUCCESS
rclcpp::Executor::remove_node
virtual void remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify=true)
Remove a node from the executor.
node_base_interface.hpp
future_return_code.hpp
rclcpp::FutureReturnCode::TIMEOUT
@ TIMEOUT
rclcpp::Executor::wait_for_work
void wait_for_work(std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
rclcpp::FutureReturnCode::INTERRUPTED
@ INTERRUPTED
rclcpp::Executor::~Executor
virtual ~Executor()
Default destructor.
rcl_wait_set_t
rclcpp::AnyExecutable
Definition: any_executable.hpp:33
rclcpp::Executor::spin_node_once
void spin_node_once(std::shared_ptr< NodeT > node, std::chrono::duration< RepT, T > timeout=std::chrono::duration< RepT, T >(-1))
Convenience function which takes Node and forwards NodeBaseInterface.
Definition: executor.hpp:140
std::runtime_error
RCLCPP_SCOPE_EXIT
#define RCLCPP_SCOPE_EXIT(code)
Definition: scope_exit.hpp:49
rclcpp::Executor::add_node
virtual void add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify=true)
Add a node to the executor.
rclcpp::Executor::get_next_executable
bool get_next_executable(AnyExecutable &any_executable, std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
rclcpp::Executor::guard_conditions_
std::list< const rcl_guard_condition_t * > guard_conditions_
Definition: executor.hpp:346
rclcpp::Executor::Executor
Executor(const rclcpp::ExecutorOptions &options=rclcpp::ExecutorOptions())
Default constructor.
rclcpp::Executor::set_memory_strategy
void set_memory_strategy(memory_strategy::MemoryStrategy::SharedPtr memory_strategy)
Support dynamic switching of the memory strategy.
std::shared_future::wait_for
T wait_for(T... args)
rclcpp::Executor::get_next_ready_executable
bool get_next_ready_executable(AnyExecutable &any_executable)
executor_options.hpp
default_context.hpp
rclcpp::Executor::spin_until_future_complete
FutureReturnCode spin_until_future_complete(const std::shared_future< ResponseT > &future, std::chrono::duration< TimeRepT, TimeT > timeout=std::chrono::duration< TimeRepT, TimeT >(-1))
Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
Definition: executor.hpp:194
rclcpp::Executor::wait_set_
rcl_wait_set_t wait_set_
Wait set for managing entities that the rmw layer waits on.
Definition: executor.hpp:332
visibility_control.hpp
std
std::mutex
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE
#define RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(...)
Definition: macros.hpp:51
rclcpp::Executor::spin_node_some
void spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node)
Add a node, complete all immediately available work, and remove the node.
rclcpp::Executor::spinning
std::atomic_bool spinning
Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins.
Definition: executor.hpp:326
rclcpp::Executor::context_
std::shared_ptr< rclcpp::Context > context_
The context associated with this executor.
Definition: executor.hpp:341
memory_strategies.hpp
utilities.hpp
memory_strategy.hpp
rclcpp::Executor::execute_subscription
static void execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
std::chrono::steady_clock::now
T now(T... args)