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