ROS 2 rclcpp + rcl - rolling  rolling-20536064
ROS 2 C++ Client Library with ROS Client Library
sequential_synchronization.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_SET_POLICIES__SEQUENTIAL_SYNCHRONIZATION_HPP_
16 #define RCLCPP__WAIT_SET_POLICIES__SEQUENTIAL_SYNCHRONIZATION_HPP_
17 
18 #include <chrono>
19 #include <functional>
20 #include <memory>
21 #include <utility>
22 
23 #include "rclcpp/client.hpp"
24 #include "rclcpp/exceptions.hpp"
25 #include "rclcpp/guard_condition.hpp"
26 #include "rclcpp/macros.hpp"
27 #include "rclcpp/service.hpp"
28 #include "rclcpp/subscription_base.hpp"
29 #include "rclcpp/subscription_wait_set_mask.hpp"
30 #include "rclcpp/timer.hpp"
31 #include "rclcpp/visibility_control.hpp"
32 #include "rclcpp/wait_result_kind.hpp"
33 #include "rclcpp/wait_set_policies/detail/synchronization_policy_common.hpp"
34 #include "rclcpp/waitable.hpp"
35 
36 namespace rclcpp
37 {
38 namespace wait_set_policies
39 {
40 
43 {
44 protected:
45  explicit SequentialSynchronization(rclcpp::Context::SharedPtr) {}
46  ~SequentialSynchronization() = default;
47 
49 
53  const std::array<std::shared_ptr<rclcpp::GuardCondition>, 0> &
55  {
56  static const std::array<std::shared_ptr<rclcpp::GuardCondition>, 0> empty{};
57  return empty;
58  }
59 
61 
64  void
66  std::shared_ptr<rclcpp::SubscriptionBase> && subscription,
68  std::function<
69  void(std::shared_ptr<rclcpp::SubscriptionBase>&&, const rclcpp::SubscriptionWaitSetMask &)
70  > add_subscription_function)
71  {
72  // Explicitly no thread synchronization.
73  add_subscription_function(std::move(subscription), mask);
74  }
75 
77 
80  void
82  std::shared_ptr<rclcpp::SubscriptionBase> && subscription,
84  std::function<
85  void(std::shared_ptr<rclcpp::SubscriptionBase>&&, const rclcpp::SubscriptionWaitSetMask &)
86  > remove_subscription_function)
87  {
88  // Explicitly no thread synchronization.
89  remove_subscription_function(std::move(subscription), mask);
90  }
91 
93 
96  void
98  std::shared_ptr<rclcpp::GuardCondition> && guard_condition,
99  std::function<void(std::shared_ptr<rclcpp::GuardCondition>&&)> add_guard_condition_function)
100  {
101  // Explicitly no thread synchronization.
102  add_guard_condition_function(std::move(guard_condition));
103  }
104 
106 
109  void
111  std::shared_ptr<rclcpp::GuardCondition> && guard_condition,
112  std::function<void(std::shared_ptr<rclcpp::GuardCondition>&&)> remove_guard_condition_function)
113  {
114  // Explicitly no thread synchronization.
115  remove_guard_condition_function(std::move(guard_condition));
116  }
117 
119 
122  void
124  std::shared_ptr<rclcpp::TimerBase> && timer,
125  std::function<void(std::shared_ptr<rclcpp::TimerBase>&&)> add_timer_function)
126  {
127  // Explicitly no thread synchronization.
128  add_timer_function(std::move(timer));
129  }
130 
132 
135  void
137  std::shared_ptr<rclcpp::TimerBase> && timer,
138  std::function<void(std::shared_ptr<rclcpp::TimerBase>&&)> remove_timer_function)
139  {
140  // Explicitly no thread synchronization.
141  remove_timer_function(std::move(timer));
142  }
143 
145 
148  void
150  std::shared_ptr<rclcpp::ClientBase> && client,
151  std::function<void(std::shared_ptr<rclcpp::ClientBase>&&)> add_client_function)
152  {
153  // Explicitly no thread synchronization.
154  add_client_function(std::move(client));
155  }
156 
158 
161  void
163  std::shared_ptr<rclcpp::ClientBase> && client,
164  std::function<void(std::shared_ptr<rclcpp::ClientBase>&&)> remove_client_function)
165  {
166  // Explicitly no thread synchronization.
167  remove_client_function(std::move(client));
168  }
169 
171 
174  void
176  std::shared_ptr<rclcpp::ServiceBase> && service,
177  std::function<void(std::shared_ptr<rclcpp::ServiceBase>&&)> add_service_function)
178  {
179  // Explicitly no thread synchronization.
180  add_service_function(std::move(service));
181  }
182 
184 
187  void
189  std::shared_ptr<rclcpp::ServiceBase> && service,
190  std::function<void(std::shared_ptr<rclcpp::ServiceBase>&&)> remove_service_function)
191  {
192  // Explicitly no thread synchronization.
193  remove_service_function(std::move(service));
194  }
195 
197 
200  void
202  std::shared_ptr<rclcpp::Waitable> && waitable,
203  std::shared_ptr<void> && associated_entity,
204  std::function<
205  void(std::shared_ptr<rclcpp::Waitable>&&, std::shared_ptr<void> &&)
206  > add_waitable_function)
207  {
208  // Explicitly no thread synchronization.
209  add_waitable_function(std::move(waitable), std::move(associated_entity));
210  }
211 
213 
216  void
218  std::shared_ptr<rclcpp::Waitable> && waitable,
219  std::function<void(std::shared_ptr<rclcpp::Waitable>&&)> remove_waitable_function)
220  {
221  // Explicitly no thread synchronization.
222  remove_waitable_function(std::move(waitable));
223  }
224 
226 
229  void
230  sync_prune_deleted_entities(std::function<void()> prune_deleted_entities_function)
231  {
232  // Explicitly no thread synchronization.
233  prune_deleted_entities_function();
234  }
235 
237  template<class WaitResultT>
238  WaitResultT
240  std::chrono::nanoseconds time_to_wait_ns,
241  std::function<void()> rebuild_rcl_wait_set,
242  std::function<rcl_wait_set_t & ()> get_rcl_wait_set,
243  std::function<WaitResultT(WaitResultKind wait_result_kind)> create_wait_result)
244  {
245  // Assumption: this function assumes that some measure has been taken to
246  // ensure none of the entities being waited on by the wait set are allowed
247  // to go out of scope and therefore be deleted.
248  // In the case of the StaticStorage policy, this is ensured because it
249  // retains shared ownership of all entites for the duration of its own life.
250  // In the case of the DynamicStorage policy, this is ensured by the function
251  // which calls this function, by acquiring shared ownership of the entites
252  // for the duration of this function.
253 
254  // Setup looping predicate.
255  auto start = std::chrono::steady_clock::now();
256  std::function<bool()> should_loop = this->create_loop_predicate(time_to_wait_ns, start);
257 
258  // Wait until exit condition is met.
259  do {
260  // Rebuild the wait set.
261  // This will resize the wait set if needed, due to e.g. adding or removing
262  // entities since the last wait, but this should never occur in static
263  // storage wait sets since they cannot be changed after construction.
264  // This will also clear the wait set and re-add all the entities, which
265  // prepares it to be waited on again.
266  rebuild_rcl_wait_set();
267 
268  rcl_wait_set_t & rcl_wait_set = get_rcl_wait_set();
269 
270  // Wait unconditionally until timeout condition occurs since we assume
271  // there are no conditions that would require the wait to stop and reset,
272  // like asynchronously adding or removing an entity, i.e. explicitly
273  // providing no thread-safety.
274 
275  // Calculate how much time there is left to wait, unless blocking indefinitely.
276  auto time_left_to_wait_ns = this->calculate_time_left_to_wait(time_to_wait_ns, start);
277 
278  // Then wait for entities to become ready.
279  rcl_ret_t ret = rcl_wait(&rcl_wait_set, time_left_to_wait_ns.count());
280  if (RCL_RET_OK == ret) {
281  // Something has become ready in the wait set, and since this class
282  // did not add anything to it, it is a user entity that is ready.
283  return create_wait_result(WaitResultKind::Ready);
284  } else if (RCL_RET_TIMEOUT == ret) {
285  // The wait set timed out, exit the loop.
286  break;
287  } else if (RCL_RET_WAIT_SET_EMPTY == ret) {
288  // Wait set was empty, return Empty.
289  return create_wait_result(WaitResultKind::Empty);
290  } else {
291  // Some other error case, throw.
292  rclcpp::exceptions::throw_from_rcl_error(ret, "rcl_wait() failed");
293  }
294  } while (should_loop());
295 
296  // Wait did not result in ready items, return timeout.
297  return create_wait_result(WaitResultKind::Timeout);
298  }
299 
300  void
301  sync_wait_result_acquire()
302  {
303  // Explicitly do nothing.
304  }
305 
306  void
307  sync_wait_result_release()
308  {
309  // Explicitly do nothing.
310  }
311 };
312 
313 } // namespace wait_set_policies
314 } // namespace rclcpp
315 
316 #endif // RCLCPP__WAIT_SET_POLICIES__SEQUENTIAL_SYNCHRONIZATION_HPP_
Options used to determine what parts of a subscription get added to or removed from a wait set.
WaitSet policy that explicitly provides no thread synchronization.
void sync_add_service(std::shared_ptr< rclcpp::ServiceBase > &&service, std::function< void(std::shared_ptr< rclcpp::ServiceBase > &&)> add_service_function)
Add service without thread-safety.
void sync_remove_service(std::shared_ptr< rclcpp::ServiceBase > &&service, std::function< void(std::shared_ptr< rclcpp::ServiceBase > &&)> remove_service_function)
Remove service without thread-safety.
void sync_add_timer(std::shared_ptr< rclcpp::TimerBase > &&timer, std::function< void(std::shared_ptr< rclcpp::TimerBase > &&)> add_timer_function)
Add timer without thread-safety.
void sync_remove_client(std::shared_ptr< rclcpp::ClientBase > &&client, std::function< void(std::shared_ptr< rclcpp::ClientBase > &&)> remove_client_function)
Remove client without thread-safety.
void sync_prune_deleted_entities(std::function< void()> prune_deleted_entities_function)
Prune deleted entities without thread-safety.
void sync_add_subscription(std::shared_ptr< rclcpp::SubscriptionBase > &&subscription, const rclcpp::SubscriptionWaitSetMask &mask, std::function< void(std::shared_ptr< rclcpp::SubscriptionBase > &&, const rclcpp::SubscriptionWaitSetMask &) > add_subscription_function)
Add subscription without thread-safety.
void sync_remove_waitable(std::shared_ptr< rclcpp::Waitable > &&waitable, std::function< void(std::shared_ptr< rclcpp::Waitable > &&)> remove_waitable_function)
Remove waitable without thread-safety.
WaitResultT sync_wait(std::chrono::nanoseconds time_to_wait_ns, std::function< void()> rebuild_rcl_wait_set, std::function< rcl_wait_set_t &()> get_rcl_wait_set, std::function< WaitResultT(WaitResultKind wait_result_kind)> create_wait_result)
Implements wait without any thread-safety.
void sync_remove_subscription(std::shared_ptr< rclcpp::SubscriptionBase > &&subscription, const rclcpp::SubscriptionWaitSetMask &mask, std::function< void(std::shared_ptr< rclcpp::SubscriptionBase > &&, const rclcpp::SubscriptionWaitSetMask &) > remove_subscription_function)
Remove guard condition without thread-safety.
const std::array< std::shared_ptr< rclcpp::GuardCondition >, 0 > & get_extra_guard_conditions()
Return any "extra" guard conditions needed to implement the synchronization policy.
void sync_add_client(std::shared_ptr< rclcpp::ClientBase > &&client, std::function< void(std::shared_ptr< rclcpp::ClientBase > &&)> add_client_function)
Add client without thread-safety.
void sync_add_guard_condition(std::shared_ptr< rclcpp::GuardCondition > &&guard_condition, std::function< void(std::shared_ptr< rclcpp::GuardCondition > &&)> add_guard_condition_function)
Add guard condition without thread-safety.
void sync_add_waitable(std::shared_ptr< rclcpp::Waitable > &&waitable, std::shared_ptr< void > &&associated_entity, std::function< void(std::shared_ptr< rclcpp::Waitable > &&, std::shared_ptr< void > &&) > add_waitable_function)
Add waitable without thread-safety.
void sync_remove_timer(std::shared_ptr< rclcpp::TimerBase > &&timer, std::function< void(std::shared_ptr< rclcpp::TimerBase > &&)> remove_timer_function)
Remove timer without thread-safety.
void sync_remove_guard_condition(std::shared_ptr< rclcpp::GuardCondition > &&guard_condition, std::function< void(std::shared_ptr< rclcpp::GuardCondition > &&)> remove_guard_condition_function)
Remove guard condition without thread-safety.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
Container for subscription's, guard condition's, etc to be waited on.
Definition: wait.h:42
#define RCL_RET_WAIT_SET_EMPTY
Given rcl_wait_set_t is empty return code.
Definition: types.h:101
#define RCL_RET_OK
Success return code.
Definition: types.h:27
#define RCL_RET_TIMEOUT
Timeout occurred return code.
Definition: types.h:31
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait(rcl_wait_set_t *wait_set, int64_t timeout)
Block until the wait set is ready or until the timeout has been exceeded.
Definition: wait.c:538