ROS 2 rclcpp + rcl - rolling  rolling-a919a6e5
ROS 2 C++ Client Library with ROS Client Library
wait_result.hpp
1 // Copyright 2020 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__WAIT_RESULT_HPP_
16 #define RCLCPP__WAIT_RESULT_HPP_
17 
18 #include <cassert>
19 #include <functional>
20 #include <iostream>
21 #include <memory>
22 #include <stdexcept>
23 #include <utility>
24 
25 #include "rcl/wait.h"
26 
27 #include "rclcpp/macros.hpp"
28 #include "rclcpp/wait_result_kind.hpp"
29 
30 #include "rclcpp/client.hpp"
31 #include "rclcpp/service.hpp"
32 #include "rclcpp/subscription_base.hpp"
33 #include "rclcpp/timer.hpp"
34 
35 namespace rclcpp
36 {
37 
38 // TODO(wjwwood): the union-like design of this class could be replaced with
39 // std::variant, when we have access to that...
41 
61 template<class WaitSetT>
62 class WaitResult final
63 {
64 public:
66 
71  static
73  from_ready_wait_result_kind(WaitSetT & wait_set)
74  {
75  return WaitResult(WaitResultKind::Ready, wait_set);
76  }
77 
79  static
82  {
83  return WaitResult(WaitResultKind::Timeout);
84  }
85 
87  static
90  {
91  return WaitResult(WaitResultKind::Empty);
92  }
93 
95  WaitResultKind
96  kind() const
97  {
98  return wait_result_kind_;
99  }
100 
102 
106  const WaitSetT &
107  get_wait_set() const
108  {
109  if (this->kind() != WaitResultKind::Ready) {
110  throw std::runtime_error("cannot access wait set when the result was not ready");
111  }
112  // This should never happen, defensive (and debug mode) check only.
113  assert(wait_set_pointer_);
114  return *wait_set_pointer_;
115  }
116 
118 
122  WaitSetT &
124  {
125  if (this->kind() != WaitResultKind::Ready) {
126  throw std::runtime_error("cannot access wait set when the result was not ready");
127  }
128  // This should never happen, defensive (and debug mode) check only.
129  assert(wait_set_pointer_);
130  return *wait_set_pointer_;
131  }
132 
133  WaitResult(WaitResult && other) noexcept
134  : wait_result_kind_(other.wait_result_kind_),
135  wait_set_pointer_(std::exchange(other.wait_set_pointer_, nullptr))
136  {}
137 
138  ~WaitResult()
139  {
140  if (wait_set_pointer_) {
141  wait_set_pointer_->wait_result_release();
142  }
143  }
144 
146 
167  std::pair<std::shared_ptr<rclcpp::TimerBase>, size_t>
168  peek_next_ready_timer(size_t start_index = 0)
169  {
170  check_wait_result_dirty();
171  auto ret = std::shared_ptr<rclcpp::TimerBase>{nullptr};
172  size_t ii = start_index;
173  if (this->kind() == WaitResultKind::Ready) {
174  auto & wait_set = this->get_wait_set();
175  auto & rcl_wait_set = wait_set.storage_get_rcl_wait_set();
176  for (; ii < wait_set.size_of_timers(); ++ii) {
177  if (rcl_wait_set.timers[ii] != nullptr) {
178  ret = wait_set.timers(ii);
179  if (ret) {
180  break;
181  }
182  }
183  }
184  }
185  return {ret, ii};
186  }
187 
189 
198  void
200  {
201  auto & wait_set = this->get_wait_set();
202  auto & rcl_wait_set = wait_set.storage_get_rcl_wait_set();
203  if (index >= wait_set.size_of_timers()) {
204  throw std::out_of_range("given timer index is out of range");
205  }
206  rcl_wait_set.timers[index] = nullptr;
207  }
208 
210  std::shared_ptr<rclcpp::SubscriptionBase>
212  {
213  check_wait_result_dirty();
214  auto ret = std::shared_ptr<rclcpp::SubscriptionBase>{nullptr};
215  if (this->kind() == WaitResultKind::Ready) {
216  auto & wait_set = this->get_wait_set();
217  auto & rcl_wait_set = wait_set.storage_get_rcl_wait_set();
218  for (size_t ii = 0; ii < wait_set.size_of_subscriptions(); ++ii) {
219  if (rcl_wait_set.subscriptions[ii] != nullptr) {
220  ret = wait_set.subscriptions(ii);
221  rcl_wait_set.subscriptions[ii] = nullptr;
222  if (ret) {
223  break;
224  }
225  }
226  }
227  }
228  return ret;
229  }
230 
232  std::shared_ptr<rclcpp::ServiceBase>
234  {
235  check_wait_result_dirty();
236  auto ret = std::shared_ptr<rclcpp::ServiceBase>{nullptr};
237  if (this->kind() == WaitResultKind::Ready) {
238  auto & wait_set = this->get_wait_set();
239  auto & rcl_wait_set = wait_set.storage_get_rcl_wait_set();
240  for (size_t ii = 0; ii < wait_set.size_of_services(); ++ii) {
241  if (rcl_wait_set.services[ii] != nullptr) {
242  ret = wait_set.services(ii);
243  rcl_wait_set.services[ii] = nullptr;
244  if (ret) {
245  break;
246  }
247  }
248  }
249  }
250  return ret;
251  }
252 
254  std::shared_ptr<rclcpp::ClientBase>
256  {
257  check_wait_result_dirty();
258  auto ret = std::shared_ptr<rclcpp::ClientBase>{nullptr};
259  if (this->kind() == WaitResultKind::Ready) {
260  auto & wait_set = this->get_wait_set();
261  auto & rcl_wait_set = wait_set.storage_get_rcl_wait_set();
262  for (size_t ii = 0; ii < wait_set.size_of_clients(); ++ii) {
263  if (rcl_wait_set.clients[ii] != nullptr) {
264  ret = wait_set.clients(ii);
265  rcl_wait_set.clients[ii] = nullptr;
266  if (ret) {
267  break;
268  }
269  }
270  }
271  }
272  return ret;
273  }
274 
276  std::shared_ptr<rclcpp::Waitable>
278  {
279  check_wait_result_dirty();
280  auto waitable = std::shared_ptr<rclcpp::Waitable>{nullptr};
281  auto data = std::shared_ptr<void>{nullptr};
282 
283  if (this->kind() == WaitResultKind::Ready) {
284  auto & wait_set = this->get_wait_set();
285  auto & rcl_wait_set = wait_set.get_rcl_wait_set();
286  while (next_waitable_index_ < wait_set.size_of_waitables()) {
287  auto cur_waitable = wait_set.waitables(next_waitable_index_++);
288  if (cur_waitable != nullptr && cur_waitable->is_ready(rcl_wait_set)) {
289  waitable = cur_waitable;
290  break;
291  }
292  }
293  }
294 
295  return waitable;
296  }
297 
298 private:
299  RCLCPP_DISABLE_COPY(WaitResult)
300 
301  explicit WaitResult(WaitResultKind wait_result_kind)
302  : wait_result_kind_(wait_result_kind)
303  {
304  // Should be enforced by the static factory methods on this class.
305  assert(WaitResultKind::Ready != wait_result_kind);
306  }
307 
308  WaitResult(WaitResultKind wait_result_kind, WaitSetT & wait_set)
309  : wait_result_kind_(wait_result_kind),
310  wait_set_pointer_(&wait_set)
311  {
312  // Should be enforced by the static factory methods on this class.
313  assert(WaitResultKind::Ready == wait_result_kind);
314  // Secure thread-safety (if provided) and shared ownership (if needed).
315  this->get_wait_set().wait_result_acquire();
316  }
317 
319  void
320  check_wait_result_dirty()
321  {
322  // In the case that the wait set was modified while the result was out,
323  // we must mark the wait result as no longer valid
324  if (wait_set_pointer_ && this->get_wait_set().wait_result_dirty_) {
325  this->wait_result_kind_ = WaitResultKind::Invalid;
326  }
327  }
328 
329  WaitResultKind wait_result_kind_;
330 
331  WaitSetT * wait_set_pointer_ = nullptr;
332 
333  size_t next_waitable_index_ = 0;
334 };
335 
336 } // namespace rclcpp
337 
338 #endif // RCLCPP__WAIT_RESULT_HPP_
Interface for introspecting a wait set after waiting on it.
Definition: wait_result.hpp:63
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.
static WaitResult from_ready_wait_result_kind(WaitSetT &wait_set)
Create WaitResult from a "ready" result.
Definition: wait_result.hpp:73
static WaitResult from_empty_wait_result_kind()
Create WaitResult from a "empty" result.
Definition: wait_result.hpp:89
static WaitResult from_timeout_wait_result_kind()
Create WaitResult from a "timeout" result.
Definition: wait_result.hpp:81
std::shared_ptr< rclcpp::ServiceBase > next_ready_service()
Get the next ready service, clearing it from the wait result.
const WaitSetT & get_wait_set() const
Return the rcl wait set.
WaitResultKind kind() const
Return the kind of the WaitResult.
Definition: wait_result.hpp:96
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.
WaitSetT & get_wait_set()
Return the rcl wait set.
std::shared_ptr< rclcpp::Waitable > next_ready_waitable()
Get the next ready waitable, clearing it from the wait result.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.