ROS 2 rclcpp + rcl - humble  humble
ROS 2 C++ Client Library with ROS Client Library
allocator_memory_strategy.hpp
1 // Copyright 2015 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__STRATEGIES__ALLOCATOR_MEMORY_STRATEGY_HPP_
16 #define RCLCPP__STRATEGIES__ALLOCATOR_MEMORY_STRATEGY_HPP_
17 
18 #include <memory>
19 #include <vector>
20 
21 #include "rcl/allocator.h"
22 
23 #include "rclcpp/allocator/allocator_common.hpp"
24 #include "rclcpp/detail/add_guard_condition_to_rcl_wait_set.hpp"
25 #include "rclcpp/memory_strategy.hpp"
26 #include "rclcpp/node.hpp"
27 #include "rclcpp/visibility_control.hpp"
28 
29 #include "rcutils/logging_macros.h"
30 
31 #include "rmw/types.h"
32 
33 namespace rclcpp
34 {
35 namespace memory_strategies
36 {
37 namespace allocator_memory_strategy
38 {
39 
41 
46 template<typename Alloc = std::allocator<void>>
48 {
49 public:
50  RCLCPP_SMART_PTR_DEFINITIONS(AllocatorMemoryStrategy<Alloc>)
51 
52  using VoidAllocTraits = typename allocator::AllocRebind<void *, Alloc>;
53  using VoidAlloc = typename VoidAllocTraits::allocator_type;
54 
55  explicit AllocatorMemoryStrategy(std::shared_ptr<Alloc> allocator)
56  {
57  allocator_ = std::make_shared<VoidAlloc>(*allocator.get());
58  }
59 
61  {
62  allocator_ = std::make_shared<VoidAlloc>();
63  }
64 
65  void add_guard_condition(const rclcpp::GuardCondition & guard_condition) override
66  {
67  for (const auto & existing_guard_condition : guard_conditions_) {
68  if (existing_guard_condition == &guard_condition) {
69  return;
70  }
71  }
72  guard_conditions_.push_back(&guard_condition);
73  }
74 
75  void remove_guard_condition(const rclcpp::GuardCondition * guard_condition) override
76  {
77  for (auto it = guard_conditions_.begin(); it != guard_conditions_.end(); ++it) {
78  if (*it == guard_condition) {
79  guard_conditions_.erase(it);
80  break;
81  }
82  }
83  }
84 
85  void clear_handles() override
86  {
87  subscription_handles_.clear();
88  service_handles_.clear();
89  client_handles_.clear();
90  timer_handles_.clear();
91  waitable_handles_.clear();
92  }
93 
94  void remove_null_handles(rcl_wait_set_t * wait_set) override
95  {
96  // TODO(jacobperron): Check if wait set sizes are what we expect them to be?
97  // e.g. wait_set->size_of_clients == client_handles_.size()
98 
99  // Important to use subscription_handles_.size() instead of wait set's size since
100  // there may be more subscriptions in the wait set due to Waitables added to the end.
101  // The same logic applies for other entities.
102  for (size_t i = 0; i < subscription_handles_.size(); ++i) {
103  if (!wait_set->subscriptions[i]) {
104  subscription_handles_[i].reset();
105  }
106  }
107  for (size_t i = 0; i < service_handles_.size(); ++i) {
108  if (!wait_set->services[i]) {
109  service_handles_[i].reset();
110  }
111  }
112  for (size_t i = 0; i < client_handles_.size(); ++i) {
113  if (!wait_set->clients[i]) {
114  client_handles_[i].reset();
115  }
116  }
117  for (size_t i = 0; i < timer_handles_.size(); ++i) {
118  if (!wait_set->timers[i]) {
119  timer_handles_[i].reset();
120  }
121  }
122  for (size_t i = 0; i < waitable_handles_.size(); ++i) {
123  if (!waitable_handles_[i]->is_ready(wait_set)) {
124  waitable_handles_[i].reset();
125  }
126  }
127 
128  subscription_handles_.erase(
129  std::remove(subscription_handles_.begin(), subscription_handles_.end(), nullptr),
130  subscription_handles_.end()
131  );
132 
133  service_handles_.erase(
134  std::remove(service_handles_.begin(), service_handles_.end(), nullptr),
135  service_handles_.end()
136  );
137 
138  client_handles_.erase(
139  std::remove(client_handles_.begin(), client_handles_.end(), nullptr),
140  client_handles_.end()
141  );
142 
143  timer_handles_.erase(
144  std::remove(timer_handles_.begin(), timer_handles_.end(), nullptr),
145  timer_handles_.end()
146  );
147 
148  waitable_handles_.erase(
149  std::remove(waitable_handles_.begin(), waitable_handles_.end(), nullptr),
150  waitable_handles_.end()
151  );
152  }
153 
154  bool collect_entities(const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
155  {
156  bool has_invalid_weak_groups_or_nodes = false;
157  for (const auto & pair : weak_groups_to_nodes) {
158  auto group = pair.first.lock();
159  auto node = pair.second.lock();
160  if (group == nullptr || node == nullptr) {
161  has_invalid_weak_groups_or_nodes = true;
162  continue;
163  }
164  if (!group || !group->can_be_taken_from().load()) {
165  continue;
166  }
167 
168  group->collect_all_ptrs(
169  [this](const rclcpp::SubscriptionBase::SharedPtr & subscription) {
170  subscription_handles_.push_back(subscription->get_subscription_handle());
171  },
172  [this](const rclcpp::ServiceBase::SharedPtr & service) {
173  service_handles_.push_back(service->get_service_handle());
174  },
175  [this](const rclcpp::ClientBase::SharedPtr & client) {
176  client_handles_.push_back(client->get_client_handle());
177  },
178  [this](const rclcpp::TimerBase::SharedPtr & timer) {
179  timer_handles_.push_back(timer->get_timer_handle());
180  },
181  [this](const rclcpp::Waitable::SharedPtr & waitable) {
182  waitable_handles_.push_back(waitable);
183  });
184  }
185 
186  return has_invalid_weak_groups_or_nodes;
187  }
188 
189  void add_waitable_handle(const rclcpp::Waitable::SharedPtr & waitable) override
190  {
191  if (nullptr == waitable) {
192  throw std::runtime_error("waitable object unexpectedly nullptr");
193  }
194  waitable_handles_.push_back(waitable);
195  }
196 
197  bool add_handles_to_wait_set(rcl_wait_set_t * wait_set) override
198  {
199  for (const std::shared_ptr<const rcl_subscription_t> & subscription : subscription_handles_) {
200  if (rcl_wait_set_add_subscription(wait_set, subscription.get(), NULL) != RCL_RET_OK) {
201  RCUTILS_LOG_ERROR_NAMED(
202  "rclcpp",
203  "Couldn't add subscription to wait set: %s", rcl_get_error_string().str);
204  return false;
205  }
206  }
207 
208  for (const std::shared_ptr<const rcl_client_t> & client : client_handles_) {
209  if (rcl_wait_set_add_client(wait_set, client.get(), NULL) != RCL_RET_OK) {
210  RCUTILS_LOG_ERROR_NAMED(
211  "rclcpp",
212  "Couldn't add client to wait set: %s", rcl_get_error_string().str);
213  return false;
214  }
215  }
216 
217  for (const std::shared_ptr<const rcl_service_t> & service : service_handles_) {
218  if (rcl_wait_set_add_service(wait_set, service.get(), NULL) != RCL_RET_OK) {
219  RCUTILS_LOG_ERROR_NAMED(
220  "rclcpp",
221  "Couldn't add service to wait set: %s", rcl_get_error_string().str);
222  return false;
223  }
224  }
225 
226  for (const std::shared_ptr<const rcl_timer_t> & timer : timer_handles_) {
227  if (rcl_wait_set_add_timer(wait_set, timer.get(), NULL) != RCL_RET_OK) {
228  RCUTILS_LOG_ERROR_NAMED(
229  "rclcpp",
230  "Couldn't add timer to wait set: %s", rcl_get_error_string().str);
231  return false;
232  }
233  }
234 
235  for (auto guard_condition : guard_conditions_) {
236  detail::add_guard_condition_to_rcl_wait_set(*wait_set, *guard_condition);
237  }
238 
239  for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
240  waitable->add_to_wait_set(wait_set);
241  }
242  return true;
243  }
244 
245  void
246  get_next_subscription(
247  rclcpp::AnyExecutable & any_exec,
248  const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
249  {
250  auto it = subscription_handles_.begin();
251  while (it != subscription_handles_.end()) {
252  auto subscription = get_subscription_by_handle(*it, weak_groups_to_nodes);
253  if (subscription) {
254  // Find the group for this handle and see if it can be serviced
255  auto group = get_group_by_subscription(subscription, weak_groups_to_nodes);
256  if (!group) {
257  // Group was not found, meaning the subscription is not valid...
258  // Remove it from the ready list and continue looking
259  it = subscription_handles_.erase(it);
260  continue;
261  }
262  if (!group->can_be_taken_from().load()) {
263  // Group is mutually exclusive and is being used, so skip it for now
264  // Leave it to be checked next time, but continue searching
265  ++it;
266  continue;
267  }
268  // Otherwise it is safe to set and return the any_exec
269  any_exec.subscription = subscription;
270  any_exec.callback_group = group;
271  any_exec.node_base = get_node_by_group(group, weak_groups_to_nodes);
272  subscription_handles_.erase(it);
273  return;
274  }
275  // Else, the subscription is no longer valid, remove it and continue
276  it = subscription_handles_.erase(it);
277  }
278  }
279 
280  void
281  get_next_service(
282  rclcpp::AnyExecutable & any_exec,
283  const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
284  {
285  auto it = service_handles_.begin();
286  while (it != service_handles_.end()) {
287  auto service = get_service_by_handle(*it, weak_groups_to_nodes);
288  if (service) {
289  // Find the group for this handle and see if it can be serviced
290  auto group = get_group_by_service(service, weak_groups_to_nodes);
291  if (!group) {
292  // Group was not found, meaning the service is not valid...
293  // Remove it from the ready list and continue looking
294  it = service_handles_.erase(it);
295  continue;
296  }
297  if (!group->can_be_taken_from().load()) {
298  // Group is mutually exclusive and is being used, so skip it for now
299  // Leave it to be checked next time, but continue searching
300  ++it;
301  continue;
302  }
303  // Otherwise it is safe to set and return the any_exec
304  any_exec.service = service;
305  any_exec.callback_group = group;
306  any_exec.node_base = get_node_by_group(group, weak_groups_to_nodes);
307  service_handles_.erase(it);
308  return;
309  }
310  // Else, the service is no longer valid, remove it and continue
311  it = service_handles_.erase(it);
312  }
313  }
314 
315  void
316  get_next_client(
317  rclcpp::AnyExecutable & any_exec,
318  const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
319  {
320  auto it = client_handles_.begin();
321  while (it != client_handles_.end()) {
322  auto client = get_client_by_handle(*it, weak_groups_to_nodes);
323  if (client) {
324  // Find the group for this handle and see if it can be serviced
325  auto group = get_group_by_client(client, weak_groups_to_nodes);
326  if (!group) {
327  // Group was not found, meaning the service is not valid...
328  // Remove it from the ready list and continue looking
329  it = client_handles_.erase(it);
330  continue;
331  }
332  if (!group->can_be_taken_from().load()) {
333  // Group is mutually exclusive and is being used, so skip it for now
334  // Leave it to be checked next time, but continue searching
335  ++it;
336  continue;
337  }
338  // Otherwise it is safe to set and return the any_exec
339  any_exec.client = client;
340  any_exec.callback_group = group;
341  any_exec.node_base = get_node_by_group(group, weak_groups_to_nodes);
342  client_handles_.erase(it);
343  return;
344  }
345  // Else, the service is no longer valid, remove it and continue
346  it = client_handles_.erase(it);
347  }
348  }
349 
350  void
351  get_next_timer(
352  rclcpp::AnyExecutable & any_exec,
353  const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
354  {
355  auto it = timer_handles_.begin();
356  while (it != timer_handles_.end()) {
357  auto timer = get_timer_by_handle(*it, weak_groups_to_nodes);
358  if (timer) {
359  // Find the group for this handle and see if it can be serviced
360  auto group = get_group_by_timer(timer, weak_groups_to_nodes);
361  if (!group) {
362  // Group was not found, meaning the timer is not valid...
363  // Remove it from the ready list and continue looking
364  it = timer_handles_.erase(it);
365  continue;
366  }
367  if (!group->can_be_taken_from().load()) {
368  // Group is mutually exclusive and is being used, so skip it for now
369  // Leave it to be checked next time, but continue searching
370  ++it;
371  continue;
372  }
373  if (!timer->call()) {
374  // timer was cancelled, skip it.
375  ++it;
376  continue;
377  }
378  // Otherwise it is safe to set and return the any_exec
379  any_exec.timer = timer;
380  any_exec.callback_group = group;
381  any_exec.node_base = get_node_by_group(group, weak_groups_to_nodes);
382  timer_handles_.erase(it);
383  return;
384  }
385  // Else, the timer is no longer valid, remove it and continue
386  it = timer_handles_.erase(it);
387  }
388  }
389 
390  void
391  get_next_waitable(
392  rclcpp::AnyExecutable & any_exec,
393  const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
394  {
395  auto it = waitable_handles_.begin();
396  while (it != waitable_handles_.end()) {
397  std::shared_ptr<Waitable> & waitable = *it;
398  if (waitable) {
399  // Find the group for this handle and see if it can be serviced
400  auto group = get_group_by_waitable(waitable, weak_groups_to_nodes);
401  if (!group) {
402  // Group was not found, meaning the waitable is not valid...
403  // Remove it from the ready list and continue looking
404  it = waitable_handles_.erase(it);
405  continue;
406  }
407  if (!group->can_be_taken_from().load()) {
408  // Group is mutually exclusive and is being used, so skip it for now
409  // Leave it to be checked next time, but continue searching
410  ++it;
411  continue;
412  }
413  // Otherwise it is safe to set and return the any_exec
414  any_exec.waitable = waitable;
415  any_exec.callback_group = group;
416  any_exec.node_base = get_node_by_group(group, weak_groups_to_nodes);
417  waitable_handles_.erase(it);
418  return;
419  }
420  // Else, the waitable is no longer valid, remove it and continue
421  it = waitable_handles_.erase(it);
422  }
423  }
424 
425  rcl_allocator_t get_allocator() override
426  {
427  return rclcpp::allocator::get_rcl_allocator<void *, VoidAlloc>(*allocator_.get());
428  }
429 
430  size_t number_of_ready_subscriptions() const override
431  {
432  size_t number_of_subscriptions = subscription_handles_.size();
433  for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
434  number_of_subscriptions += waitable->get_number_of_ready_subscriptions();
435  }
436  return number_of_subscriptions;
437  }
438 
439  size_t number_of_ready_services() const override
440  {
441  size_t number_of_services = service_handles_.size();
442  for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
443  number_of_services += waitable->get_number_of_ready_services();
444  }
445  return number_of_services;
446  }
447 
448  size_t number_of_ready_events() const override
449  {
450  size_t number_of_events = 0;
451  for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
452  number_of_events += waitable->get_number_of_ready_events();
453  }
454  return number_of_events;
455  }
456 
457  size_t number_of_ready_clients() const override
458  {
459  size_t number_of_clients = client_handles_.size();
460  for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
461  number_of_clients += waitable->get_number_of_ready_clients();
462  }
463  return number_of_clients;
464  }
465 
466  size_t number_of_guard_conditions() const override
467  {
468  size_t number_of_guard_conditions = guard_conditions_.size();
469  for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
470  number_of_guard_conditions += waitable->get_number_of_ready_guard_conditions();
471  }
472  return number_of_guard_conditions;
473  }
474 
475  size_t number_of_ready_timers() const override
476  {
477  size_t number_of_timers = timer_handles_.size();
478  for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
479  number_of_timers += waitable->get_number_of_ready_timers();
480  }
481  return number_of_timers;
482  }
483 
484  size_t number_of_waitables() const override
485  {
486  return waitable_handles_.size();
487  }
488 
489 private:
490  template<typename T>
491  using VectorRebind =
492  std::vector<T, typename std::allocator_traits<Alloc>::template rebind_alloc<T>>;
493 
494  VectorRebind<const rclcpp::GuardCondition *> guard_conditions_;
495 
496  VectorRebind<std::shared_ptr<const rcl_subscription_t>> subscription_handles_;
497  VectorRebind<std::shared_ptr<const rcl_service_t>> service_handles_;
498  VectorRebind<std::shared_ptr<const rcl_client_t>> client_handles_;
499  VectorRebind<std::shared_ptr<const rcl_timer_t>> timer_handles_;
500  VectorRebind<std::shared_ptr<Waitable>> waitable_handles_;
501 
502  std::shared_ptr<VoidAlloc> allocator_;
503 };
504 
505 } // namespace allocator_memory_strategy
506 } // namespace memory_strategies
507 } // namespace rclcpp
508 
509 #endif // RCLCPP__STRATEGIES__ALLOCATOR_MEMORY_STRATEGY_HPP_
rcutils_allocator_t rcl_allocator_t
Encapsulation of an allocator.
Definition: allocator.h:31
A condition that can be waited on in a single wait set and asynchronously triggered.
Delegate for handling memory allocations while the Executor is executing.
Delegate for handling memory allocations while the Executor is executing.
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
const rcl_timer_t ** timers
Storage for timer pointers.
Definition: wait.h:52
const rcl_service_t ** services
Storage for service pointers.
Definition: wait.h:60
const rcl_client_t ** clients
Storage for client pointers.
Definition: wait.h:56
const rcl_subscription_t ** subscriptions
Storage for subscription pointers.
Definition: wait.h:44
#define RCL_RET_OK
Success return code.
Definition: types.h:26
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_subscription(rcl_wait_set_t *wait_set, const rcl_subscription_t *subscription, size_t *index)
Store a pointer to the given subscription in the next empty spot in the set.
Definition: wait.c:318
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_service(rcl_wait_set_t *wait_set, const rcl_service_t *service, size_t *index)
Store a pointer to the service in the next empty spot in the set.
Definition: wait.c:499
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_timer(rcl_wait_set_t *wait_set, const rcl_timer_t *timer, size_t *index)
Store a pointer to the timer in the next empty spot in the set.
Definition: wait.c:468
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_client(rcl_wait_set_t *wait_set, const rcl_client_t *client, size_t *index)
Store a pointer to the client in the next empty spot in the set.
Definition: wait.c:488