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 <string>
26 #include <vector>
27 
28 #include "rcl/guard_condition.h"
29 #include "rcl/wait.h"
30 
34 #include "rclcpp/utilities.hpp"
36 
37 namespace rclcpp
38 {
39 
40 // Forward declaration is used in convenience method signature.
41 class Node;
42 
43 namespace executor
44 {
45 
47 
53 
56 operator<<(std::ostream & os, const FutureReturnCode & future_return_code);
57 
60 to_string(const FutureReturnCode & future_return_code);
61 
63 
67 {
68  memory_strategy::MemoryStrategy::SharedPtr memory_strategy;
69  size_t max_conditions = 0;
70 };
71 
72 static inline ExecutorArgs create_default_executor_arguments()
73 {
74  ExecutorArgs args;
76  args.max_conditions = 0;
77  return args;
78 }
79 
81 
90 class Executor
91 {
92 public:
94 
95 
96  // \param[in] ms The memory strategy to be used with this executor.
98  explicit Executor(const ExecutorArgs & args = create_default_executor_arguments());
99 
102  virtual ~Executor();
103 
105  // It is up to the implementation of Executor to implement spin.
106  virtual void
107  spin() = 0;
108 
110 
118  virtual void
119  add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
120 
123  virtual void
124  add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
125 
127 
134  virtual void
135  remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
136 
139  virtual void
140  remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
141 
143 
149  template<typename T = std::milli>
150  void
152  rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
154  {
156  node,
157  std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
158  );
159  }
160 
162  template<typename NodeT = rclcpp::Node, typename T = std::milli>
163  void
167  {
169  node->get_node_base_interface(),
171  );
172  }
173 
175 
179  void
180  spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node);
181 
184  void
186 
188 
195  virtual void
196  spin_some();
197 
199  virtual void
201 
203 
212  template<typename ResponseT, typename TimeT = std::milli>
217  {
218  // TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
219  // inside a callback executed by an executor.
220 
221  // Check the future before entering the while loop.
222  // If the future is already complete, don't try to spin.
223  std::future_status status = future.wait_for(std::chrono::seconds(0));
224  if (status == std::future_status::ready) {
226  }
227 
228  auto end_time = std::chrono::steady_clock::now();
230  timeout);
231  if (timeout_ns > std::chrono::nanoseconds::zero()) {
232  end_time += timeout_ns;
233  }
234  std::chrono::nanoseconds timeout_left = timeout_ns;
235 
236  while (rclcpp::ok()) {
237  // Do one item of work.
238  spin_once(timeout_left);
239  // Check if the future is set, return SUCCESS if it is.
240  status = future.wait_for(std::chrono::seconds(0));
241  if (status == std::future_status::ready) {
243  }
244  // If the original timeout is < 0, then this is blocking, never TIMEOUT.
245  if (timeout_ns < std::chrono::nanoseconds::zero()) {
246  continue;
247  }
248  // Otherwise check if we still have time to wait, return TIMEOUT if not.
249  auto now = std::chrono::steady_clock::now();
250  if (now >= end_time) {
252  }
253  // Subtract the elapsed time from the original timeout.
254  timeout_left = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - now);
255  }
256 
257  // The future did not complete before ok() returned false, return INTERRUPTED.
259  }
260 
262  /* This function can be called asynchonously from any thread. */
264  void
265  cancel();
266 
268 
274  void
275  set_memory_strategy(memory_strategy::MemoryStrategy::SharedPtr memory_strategy);
276 
277 protected:
279  void
281  rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
282  std::chrono::nanoseconds timeout);
283 
285 
289  void
291 
293  static void
295  rclcpp::SubscriptionBase::SharedPtr subscription);
296 
298  static void
300  rclcpp::SubscriptionBase::SharedPtr subscription);
301 
303  static void
304  execute_timer(rclcpp::TimerBase::SharedPtr timer);
305 
307  static void
308  execute_service(rclcpp::ServiceBase::SharedPtr service);
309 
311  static void
312  execute_client(rclcpp::ClientBase::SharedPtr client);
313 
315  void
317 
319  rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
320  get_node_by_group(rclcpp::callback_group::CallbackGroup::SharedPtr group);
321 
323  rclcpp::callback_group::CallbackGroup::SharedPtr
324  get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
325 
327  void
328  get_next_timer(AnyExecutable & any_exec);
329 
331  bool
332  get_next_ready_executable(AnyExecutable & any_executable);
333 
335  bool
337  AnyExecutable & any_executable,
339 
341  std::atomic_bool spinning;
342 
345 
348 
350  memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
351 
352 private:
354 
356 };
357 
358 } // namespace executor
359 } // namespace rclcpp
360 
361 #endif // RCLCPP__EXECUTOR_HPP_
bool get_next_ready_executable(AnyExecutable &any_executable)
static void execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
Definition: executor.hpp:66
static void execute_timer(rclcpp::TimerBase::SharedPtr timer)
#define RCLCPP_DISABLE_COPY(...)
Definition: macros.hpp:26
void execute_any_executable(AnyExecutable &any_exec)
Find the next available executable and do the work associated with it.
virtual void spin_some()
Complete all available queued work without blocking.
void spin_node_once(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node, std::chrono::duration< int64_t, T > timeout=std::chrono::duration< int64_t, T >(-1))
Add a node to executor, execute the next available unit of work, and remove the node.
Definition: executor.hpp:151
void wait_for_work(std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
Definition: allocator_common.hpp:24
T duration_cast(T... args)
std::ostream & operator<<(std::ostream &os, const FutureReturnCode &future_return_code)
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr get_node_by_group(rclcpp::callback_group::CallbackGroup::SharedPtr group)
rcl_wait_set_t rcl_get_zero_initialized_wait_set(void)
memory_strategy::MemoryStrategy::SharedPtr create_default_strategy()
rcl_guard_condition_t rcl_get_zero_initialized_guard_condition(void)
void spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node)
Add a node, complete all immediately available work, and remove the node.
void set_memory_strategy(memory_strategy::MemoryStrategy::SharedPtr memory_strategy)
Support dynamic switching of the memory strategy.
void spin_node_once_nanoseconds(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node, std::chrono::nanoseconds timeout)
std::string to_string(const FutureReturnCode &future_return_code)
void spin_node_once(std::shared_ptr< NodeT > node, std::chrono::duration< int64_t, T > timeout=std::chrono::duration< int64_t, T >(-1))
Convenience function which takes Node and forwards NodeBaseInterface.
Definition: executor.hpp:164
size_t max_conditions
Definition: executor.hpp:69
virtual void remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify=true)
Remove a node from the executor.
memory_strategy::MemoryStrategy::SharedPtr memory_strategy_
The memory strategy: an interface for handling user-defined memory allocation strategies.
Definition: executor.hpp:350
static void execute_service(rclcpp::ServiceBase::SharedPtr service)
virtual ~Executor()
Default destructor.
static void execute_client(rclcpp::ClientBase::SharedPtr client)
bool get_next_executable(AnyExecutable &any_executable, std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
virtual void add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify=true)
Add a node to the executor.
Coordinate the order and timing of available communication tasks.
Definition: executor.hpp:90
#define RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(...)
Definition: macros.hpp:51
virtual void spin()=0
Do work periodically as it becomes available to us. Blocking call, may block indefinitely.
Executor(const ExecutorArgs &args=create_default_executor_arguments())
Default constructor.
FutureReturnCode
Return codes to be used with spin_until_future_complete.
Definition: executor.hpp:52
FutureReturnCode spin_until_future_complete(std::shared_future< ResponseT > &future, std::chrono::duration< int64_t, TimeT > timeout=std::chrono::duration< int64_t, TimeT >(-1))
Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
Definition: executor.hpp:214
#define RCLCPP_PUBLIC
Definition: visibility_control.hpp:50
bool ok()
Check rclcpp&#39;s status.
void get_next_timer(AnyExecutable &any_exec)
rclcpp::callback_group::CallbackGroup::SharedPtr get_group_by_timer(rclcpp::TimerBase::SharedPtr timer)
Definition: any_executable.hpp:34
T wait_for(T... args)
void cancel()
Cancel any running spin* function, causing it to return.
virtual void spin_once(std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
static void execute_intra_process_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
rcl_guard_condition_t interrupt_guard_condition_
Guard condition for signaling the rmw layer to wake up for special events.
Definition: executor.hpp:344
rcl_wait_set_t wait_set_
Wait set for managing entities that the rmw layer waits on.
Definition: executor.hpp:347
std::atomic_bool spinning
Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins...
Definition: executor.hpp:341
memory_strategy::MemoryStrategy::SharedPtr memory_strategy
Definition: executor.hpp:68