ROS 2 rclcpp + rcl - kilted  kilted
ROS 2 C++ Client Library with ROS Client Library
message_pool_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__MESSAGE_POOL_MEMORY_STRATEGY_HPP_
16 #define RCLCPP__STRATEGIES__MESSAGE_POOL_MEMORY_STRATEGY_HPP_
17 
18 #include <array>
19 #include <cstring>
20 #include <memory>
21 #include <mutex>
22 #include <stdexcept>
23 #include <type_traits>
24 
25 #include "rosidl_runtime_cpp/traits.hpp"
26 
27 #include "rclcpp/logger.hpp"
28 #include "rclcpp/logging.hpp"
29 #include "rclcpp/macros.hpp"
30 #include "rclcpp/message_memory_strategy.hpp"
31 #include "rclcpp/visibility_control.hpp"
32 
33 namespace rclcpp
34 {
35 namespace strategies
36 {
37 namespace message_pool_memory_strategy
38 {
39 
41 
47 template<
48  typename MessageT,
49  size_t Size,
50  typename std::enable_if<
51  rosidl_generator_traits::has_fixed_size<MessageT>::value
52  >::type * = nullptr
53 >
56 {
57 public:
58  RCLCPP_SMART_PTR_DEFINITIONS(MessagePoolMemoryStrategy)
59 
61  {
62  pool_mutex_ = std::make_shared<std::mutex>();
63 
64  pool_ = std::shared_ptr<std::array<MessageT *, Size>>(
65  new std::array<MessageT *, Size>,
66  [](std::array<MessageT *, Size> * arr) {
67  for (size_t i = 0; i < Size; ++i) {
68  free((*arr)[i]);
69  }
70  delete arr;
71  });
72 
73  free_list_ = std::make_shared<CircularArray<Size>>();
74 
75  for (size_t i = 0; i < Size; ++i) {
76  (*pool_)[i] = static_cast<MessageT *>(malloc(sizeof(MessageT)));
77  free_list_->push_back(i);
78  }
79  }
80 
82 
87  std::shared_ptr<MessageT> borrow_message()
88  {
89  std::lock_guard<std::mutex> lock(*pool_mutex_);
90  if (free_list_->size() == 0) {
91  throw std::runtime_error("No more free slots in the pool");
92  }
93 
94  size_t current_index = free_list_->pop_front();
95 
96  return std::shared_ptr<MessageT>(
97  new((*pool_)[current_index]) MessageT(),
98  [pool = this->pool_, pool_mutex = this->pool_mutex_,
99  free_list = this->free_list_](MessageT * p) {
100  std::lock_guard<std::mutex> lock(*pool_mutex);
101  for (size_t i = 0; i < Size; ++i) {
102  if ((*pool)[i] == p) {
103  p->~MessageT();
104  free_list->push_back(i);
105  break;
106  }
107  }
108  });
109  }
110 
112 
117  void return_message([[maybe_unused]] std::shared_ptr<MessageT> & msg)
118  {
119  // This function is intentionally left empty.
120  }
121 
122 protected:
123  template<size_t N>
125  {
126 public:
127  void push_back(const size_t v)
128  {
129  if (size_ + 1 > N) {
130  throw std::runtime_error("Tried to push too many items into the array");
131  }
132  array_[(front_ + size_) % N] = v;
133  ++size_;
134  }
135 
136  size_t pop_front()
137  {
138  if (size_ < 1) {
139  throw std::runtime_error("Tried to pop item from empty array");
140  }
141 
142  size_t val = array_[front_];
143 
144  front_ = (front_ + 1) % N;
145  --size_;
146 
147  return val;
148  }
149 
150  size_t size() const
151  {
152  return size_;
153  }
154 
155 private:
156  size_t front_ = 0;
157  size_t size_ = 0;
158  std::array<size_t, N> array_;
159  };
160 
161  // It's very important that these are shared_ptrs, since users of this class might hold a
162  // reference to a pool item longer than the lifetime of the class. In that scenario, the
163  // shared_ptr ensures that the lifetime of these variables outlives this class, and hence ensures
164  // the custom destructor for each pool item can successfully run.
165  std::shared_ptr<std::mutex> pool_mutex_;
166  std::shared_ptr<std::array<MessageT *, Size>> pool_;
167  std::shared_ptr<CircularArray<Size>> free_list_;
168 };
169 
170 } // namespace message_pool_memory_strategy
171 } // namespace strategies
172 } // namespace rclcpp
173 
174 #endif // RCLCPP__STRATEGIES__MESSAGE_POOL_MEMORY_STRATEGY_HPP_
Default allocation strategy for messages received by subscriptions.
std::shared_ptr< MessageT > borrow_message()
Borrow a message from the message pool.
void return_message([[maybe_unused]] std::shared_ptr< MessageT > &msg)
Return a message to the message pool.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.