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 
36 #include "rclcpp/utilities.hpp"
38 
39 namespace rclcpp
40 {
41 
42 // Forward declaration is used in convenience method signature.
43 class Node;
44 
45 namespace executor
46 {
47 
49 
56 
59 operator<<(std::ostream & os, const FutureReturnCode & future_return_code);
60 
63 to_string(const FutureReturnCode & future_return_code);
64 
66 
70 {
72  : memory_strategy(memory_strategies::create_default_strategy()),
73  context(rclcpp::contexts::default_context::get_global_default_context()),
74  max_conditions(0)
75  {}
76 
77  memory_strategy::MemoryStrategy::SharedPtr memory_strategy;
80 };
81 
82 static inline ExecutorArgs create_default_executor_arguments()
83 {
84  return ExecutorArgs();
85 }
86 
88 
97 class Executor
98 {
99 public:
101 
102 
103  // \param[in] ms The memory strategy to be used with this executor.
105  explicit Executor(const ExecutorArgs & args = ExecutorArgs());
106 
109  virtual ~Executor();
110 
112  // It is up to the implementation of Executor to implement spin.
113  virtual void
114  spin() = 0;
115 
117 
125  virtual void
126  add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
127 
130  virtual void
131  add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
132 
134 
141  virtual void
142  remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
143 
146  virtual void
147  remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
148 
150 
156  template<typename RepT = int64_t, typename T = std::milli>
157  void
159  rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
161  {
162  return spin_node_once_nanoseconds(
163  node,
164  std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
165  );
166  }
167 
169  template<typename NodeT = rclcpp::Node, typename RepT = int64_t, typename T = std::milli>
170  void
174  {
175  return spin_node_once_nanoseconds(
176  node->get_node_base_interface(),
178  );
179  }
180 
182 
186  void
187  spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node);
188 
191  void
192  spin_node_some(std::shared_ptr<rclcpp::Node> node);
193 
195 
206  virtual void
208 
210  virtual void
211  spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
212 
214 
223  template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
228  {
229  // TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
230  // inside a callback executed by an executor.
231 
232  // Check the future before entering the while loop.
233  // If the future is already complete, don't try to spin.
234  std::future_status status = future.wait_for(std::chrono::seconds(0));
235  if (status == std::future_status::ready) {
237  }
238 
239  auto end_time = std::chrono::steady_clock::now();
241  timeout);
242  if (timeout_ns > std::chrono::nanoseconds::zero()) {
243  end_time += timeout_ns;
244  }
245  std::chrono::nanoseconds timeout_left = timeout_ns;
246 
247  while (rclcpp::ok(this->context_)) {
248  // Do one item of work.
249  spin_once(timeout_left);
250  // Check if the future is set, return SUCCESS if it is.
251  status = future.wait_for(std::chrono::seconds(0));
252  if (status == std::future_status::ready) {
254  }
255  // If the original timeout is < 0, then this is blocking, never TIMEOUT.
256  if (timeout_ns < std::chrono::nanoseconds::zero()) {
257  continue;
258  }
259  // Otherwise check if we still have time to wait, return TIMEOUT if not.
260  auto now = std::chrono::steady_clock::now();
261  if (now >= end_time) {
263  }
264  // Subtract the elapsed time from the original timeout.
265  timeout_left = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - now);
266  }
267 
268  // The future did not complete before ok() returned false, return INTERRUPTED.
270  }
271 
273  /* This function can be called asynchonously from any thread. */
275  void
276  cancel();
277 
279 
285  void
286  set_memory_strategy(memory_strategy::MemoryStrategy::SharedPtr memory_strategy);
287 
288 protected:
290  void
291  spin_node_once_nanoseconds(
292  rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
293  std::chrono::nanoseconds timeout);
294 
296 
300  void
301  execute_any_executable(AnyExecutable & any_exec);
302 
304  static void
305  execute_subscription(
307 
309  static void
310  execute_timer(rclcpp::TimerBase::SharedPtr timer);
311 
313  static void
314  execute_service(rclcpp::ServiceBase::SharedPtr service);
315 
317  static void
318  execute_client(rclcpp::ClientBase::SharedPtr client);
319 
321  void
322  wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
323 
325  rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
326  get_node_by_group(rclcpp::callback_group::CallbackGroup::SharedPtr group);
327 
329  rclcpp::callback_group::CallbackGroup::SharedPtr
330  get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
331 
333  bool
334  get_next_ready_executable(AnyExecutable & any_executable);
335 
337  bool
338  get_next_executable(
339  AnyExecutable & any_executable,
341 
343  std::atomic_bool spinning;
344 
347 
350 
351  // Mutex to protect the subsequent memory_strategy_.
353 
355  memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
356 
359 
360 private:
361  RCLCPP_DISABLE_COPY(Executor)
362 
365 };
366 
367 } // namespace executor
368 } // namespace rclcpp
369 
370 #endif // RCLCPP__EXECUTOR_HPP_
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:158
DefaultContext::SharedPtr get_global_default_context()
#define RCLCPP_DISABLE_COPY(...)
Definition: macros.hpp:26
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:171
std::atomic_bool spinning
Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins...
Definition: executor.hpp:343
FutureReturnCode spin_until_future_complete(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:225
Definition: any_executable.hpp:35
This header provides the get_node_base_interface() template function.
Definition: allocator_common.hpp:24
T duration_cast(T... args)
std::ostream & operator<<(std::ostream &os, const FutureReturnCode &future_return_code)
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)
std::string to_string(const FutureReturnCode &future_return_code)
std::shared_ptr< rclcpp::Context > context
Definition: executor.hpp:78
memory_strategy::MemoryStrategy::SharedPtr memory_strategy_
The memory strategy: an interface for handling user-defined memory allocation strategies.
Definition: executor.hpp:355
Coordinate the order and timing of available communication tasks.
Definition: executor.hpp:97
ExecutorArgs()
Definition: executor.hpp:71
void spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
Create a default single-threaded executor and execute any immediately available work.
#define RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(...)
Definition: macros.hpp:51
FutureReturnCode
Return codes to be used with spin_until_future_complete.
Definition: executor.hpp:55
#define RCLCPP_PUBLIC
Definition: visibility_control.hpp:50
Set the data type used in the intra-process buffer as std::shared_ptr<MessageT>
bool ok(rclcpp::Context::SharedPtr context=nullptr)
Check rclcpp&#39;s status.
size_t max_conditions
Definition: executor.hpp:79
std::mutex memory_strategy_mutex_
Definition: executor.hpp:352
T wait_for(T... args)
memory_strategy::MemoryStrategy::SharedPtr memory_strategy
Definition: executor.hpp:77
Definition: executor.hpp:69
void spin(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
Create a default single-threaded executor and spin the specified node.
std::shared_ptr< rclcpp::Context > context_
The context associated with this executor.
Definition: executor.hpp:358