/src/Fast-DDS/include/fastrtps/utils/ProxyPool.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). |
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 | | /*! |
16 | | * @file ProxyPool.hpp |
17 | | */ |
18 | | |
19 | | #ifndef FASTRTPS_UTILS_PROXY_POOL_HPP_ |
20 | | #define FASTRTPS_UTILS_PROXY_POOL_HPP_ |
21 | | |
22 | | #include <array> |
23 | | #include <bitset> |
24 | | #include <cassert> |
25 | | #include <condition_variable> |
26 | | #include <memory> |
27 | | #include <mutex> |
28 | | |
29 | | #if defined(__has_include) && __has_include(<version>) |
30 | | # include <version> |
31 | | #endif // if defined(__has_include) && __has_include(<version>) |
32 | | |
33 | | namespace eprosima { |
34 | | |
35 | | // unnamed namespace for isolation |
36 | | namespace { |
37 | | |
38 | | // Detect if integer_sequence is availalbe |
39 | | #if defined(__cpp_lib_integer_sequence) \ |
40 | | && ((__cpp_lib_integer_sequence <= _MSVC_LANG) \ |
41 | | || (__cpp_lib_integer_sequence <= __cplusplus)) |
42 | | |
43 | | // Array initialization usin C++14 |
44 | | template<class P, size_t... Ints> |
45 | | std::array<P, sizeof...(Ints)> make_array( |
46 | | P&& i, |
47 | | std::index_sequence<Ints...> is) |
48 | | { |
49 | | return { (Ints == is.size() - 1 ? std::move(i) : i)...}; |
50 | | } |
51 | | |
52 | | template<size_t N, class P> |
53 | | std::array<P, N> make_array( |
54 | | P&& i) |
55 | | { |
56 | | return make_array<P>(std::move(i), std::make_index_sequence<N>{}); |
57 | | } |
58 | | |
59 | | #else // C++11 fallback |
60 | | |
61 | | template<size_t N, class P, class ... Ts> |
62 | | std::array<P, N> make_array( |
63 | | P&& i, |
64 | | Ts&&... args); |
65 | | |
66 | | template<bool, size_t N, class ... Ts> |
67 | | struct make_array_choice |
68 | | { |
69 | | template<class P> |
70 | | static std::array<P, N> res( |
71 | | P&& i, |
72 | | Ts&&... args) |
73 | 0 | { |
74 | 0 | P tmp(i); |
75 | 0 | return make_array<N>(std::move(i), std::move(tmp), std::move(args)...); |
76 | 0 | } Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::ReaderProxyData, 4ul> eprosima::(anonymous namespace)::make_array_choice<false, 4ul>::res<eprosima::fastrtps::rtps::ReaderProxyData>(eprosima::fastrtps::rtps::ReaderProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::ReaderProxyData, 4ul> eprosima::(anonymous namespace)::make_array_choice<false, 4ul, eprosima::fastrtps::rtps::ReaderProxyData>::res<eprosima::fastrtps::rtps::ReaderProxyData>(eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::ReaderProxyData, 4ul> eprosima::(anonymous namespace)::make_array_choice<false, 4ul, eprosima::fastrtps::rtps::ReaderProxyData, eprosima::fastrtps::rtps::ReaderProxyData>::res<eprosima::fastrtps::rtps::ReaderProxyData>(eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::WriterProxyData, 4ul> eprosima::(anonymous namespace)::make_array_choice<false, 4ul>::res<eprosima::fastrtps::rtps::WriterProxyData>(eprosima::fastrtps::rtps::WriterProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::WriterProxyData, 4ul> eprosima::(anonymous namespace)::make_array_choice<false, 4ul, eprosima::fastrtps::rtps::WriterProxyData>::res<eprosima::fastrtps::rtps::WriterProxyData>(eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::WriterProxyData, 4ul> eprosima::(anonymous namespace)::make_array_choice<false, 4ul, eprosima::fastrtps::rtps::WriterProxyData, eprosima::fastrtps::rtps::WriterProxyData>::res<eprosima::fastrtps::rtps::WriterProxyData>(eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&) |
77 | | |
78 | | }; |
79 | | |
80 | | template<size_t N, class ... Ts> |
81 | | struct make_array_choice<true, N, Ts...> |
82 | | { |
83 | | template<class P> |
84 | | static std::array<P, N> res( |
85 | | P&& i, |
86 | | Ts&&... args) |
87 | 0 | { |
88 | 0 | return {std::move(i), std::move(args)...}; |
89 | 0 | } Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::ReaderProxyData, 4ul> eprosima::(anonymous namespace)::make_array_choice<true, 4ul, eprosima::fastrtps::rtps::ReaderProxyData, eprosima::fastrtps::rtps::ReaderProxyData, eprosima::fastrtps::rtps::ReaderProxyData>::res<eprosima::fastrtps::rtps::ReaderProxyData>(eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::WriterProxyData, 4ul> eprosima::(anonymous namespace)::make_array_choice<true, 4ul, eprosima::fastrtps::rtps::WriterProxyData, eprosima::fastrtps::rtps::WriterProxyData, eprosima::fastrtps::rtps::WriterProxyData>::res<eprosima::fastrtps::rtps::WriterProxyData>(eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&) |
90 | | |
91 | | }; |
92 | | |
93 | | template<size_t N, class P, class ... Ts> |
94 | | std::array<P, N> make_array( |
95 | | P&& i, |
96 | | Ts&&... args) |
97 | 0 | { |
98 | 0 | return make_array_choice < N == (sizeof...(Ts) + 1), N, Ts ... > ::res(std::move(i), std::move(args)...); |
99 | 0 | } Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::ReaderProxyData, 4ul> eprosima::(anonymous namespace)::make_array<4ul, eprosima::fastrtps::rtps::ReaderProxyData>(eprosima::fastrtps::rtps::ReaderProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::ReaderProxyData, 4ul> eprosima::(anonymous namespace)::make_array<4ul, eprosima::fastrtps::rtps::ReaderProxyData, eprosima::fastrtps::rtps::ReaderProxyData>(eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::ReaderProxyData, 4ul> eprosima::(anonymous namespace)::make_array<4ul, eprosima::fastrtps::rtps::ReaderProxyData, eprosima::fastrtps::rtps::ReaderProxyData, eprosima::fastrtps::rtps::ReaderProxyData>(eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::ReaderProxyData, 4ul> eprosima::(anonymous namespace)::make_array<4ul, eprosima::fastrtps::rtps::ReaderProxyData, eprosima::fastrtps::rtps::ReaderProxyData, eprosima::fastrtps::rtps::ReaderProxyData, eprosima::fastrtps::rtps::ReaderProxyData>(eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&, eprosima::fastrtps::rtps::ReaderProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::WriterProxyData, 4ul> eprosima::(anonymous namespace)::make_array<4ul, eprosima::fastrtps::rtps::WriterProxyData>(eprosima::fastrtps::rtps::WriterProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::WriterProxyData, 4ul> eprosima::(anonymous namespace)::make_array<4ul, eprosima::fastrtps::rtps::WriterProxyData, eprosima::fastrtps::rtps::WriterProxyData>(eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::WriterProxyData, 4ul> eprosima::(anonymous namespace)::make_array<4ul, eprosima::fastrtps::rtps::WriterProxyData, eprosima::fastrtps::rtps::WriterProxyData, eprosima::fastrtps::rtps::WriterProxyData>(eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&) Unexecuted instantiation: PDP.cpp:std::__1::array<eprosima::fastrtps::rtps::WriterProxyData, 4ul> eprosima::(anonymous namespace)::make_array<4ul, eprosima::fastrtps::rtps::WriterProxyData, eprosima::fastrtps::rtps::WriterProxyData, eprosima::fastrtps::rtps::WriterProxyData, eprosima::fastrtps::rtps::WriterProxyData>(eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&, eprosima::fastrtps::rtps::WriterProxyData&&) |
100 | | |
101 | | #endif // defined(__cpp_lib_integer_sequence) |
102 | | |
103 | | } // namespace |
104 | | |
105 | | template< class Proxy, std::size_t N = 4> |
106 | | class ProxyPool |
107 | | { |
108 | | mutable std::mutex mtx_; |
109 | | std::condition_variable cv_; |
110 | | std::array<Proxy, N> heap_; |
111 | | std::bitset<N> mask_; |
112 | | |
113 | | // unique_ptr<Proxy> deleters |
114 | | class D |
115 | | { |
116 | | // Because ProxyPool will be destroy after all the proxies are returned |
117 | | // this reference is always valid |
118 | | ProxyPool& pool_; |
119 | | |
120 | | friend class ProxyPool; |
121 | | |
122 | | D( |
123 | | ProxyPool* pool) |
124 | | : pool_(*pool) |
125 | 0 | { |
126 | 0 | } Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::ReaderProxyData, 4ul>::D::D(eprosima::ProxyPool<eprosima::fastrtps::rtps::ReaderProxyData, 4ul>*) Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::WriterProxyData, 4ul>::D::D(eprosima::ProxyPool<eprosima::fastrtps::rtps::WriterProxyData, 4ul>*) |
127 | | |
128 | | public: |
129 | | |
130 | | void operator ()( |
131 | | Proxy* p) const |
132 | 0 | { |
133 | 0 | pool_.set_back(p); |
134 | 0 | } Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::WriterProxyData, 4ul>::D::operator()(eprosima::fastrtps::rtps::WriterProxyData*) const Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::ReaderProxyData, 4ul>::D::operator()(eprosima::fastrtps::rtps::ReaderProxyData*) const |
135 | | |
136 | | } |
137 | | deleter_; |
138 | | |
139 | | friend class D; |
140 | | |
141 | | /* |
142 | | * Return an available proxy to the pool. |
143 | | * @param p pointer to the proxy. |
144 | | */ |
145 | | void set_back( |
146 | | Proxy* p) noexcept |
147 | 0 | { |
148 | 0 | std::size_t idx = p - heap_.data(); |
149 | |
|
150 | 0 | std::lock_guard<std::mutex> _(mtx_); |
151 | | |
152 | | // check is not there |
153 | 0 | assert(!mask_.test(idx)); |
154 | | |
155 | | // return the resource |
156 | 0 | mask_.set(idx); |
157 | 0 | } Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::WriterProxyData, 4ul>::set_back(eprosima::fastrtps::rtps::WriterProxyData*) Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::ReaderProxyData, 4ul>::set_back(eprosima::fastrtps::rtps::ReaderProxyData*) |
158 | | |
159 | | public: |
160 | | |
161 | | using smart_ptr = std::unique_ptr<Proxy, D&>; |
162 | | |
163 | | /* |
164 | | * Constructor of the pool object. |
165 | | * @param init Initialization value for all the proxies. |
166 | | */ |
167 | | ProxyPool( |
168 | | Proxy&& init) |
169 | | : heap_(make_array<N>(std::move(init))) |
170 | | , deleter_(this) |
171 | 0 | { |
172 | | // make all resources available |
173 | 0 | mask_.set(); |
174 | 0 | } Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::ReaderProxyData, 4ul>::ProxyPool(eprosima::fastrtps::rtps::ReaderProxyData&&) Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::WriterProxyData, 4ul>::ProxyPool(eprosima::fastrtps::rtps::WriterProxyData&&) |
175 | | |
176 | | /* |
177 | | * Destructor for the pool object. |
178 | | * It waits till all the proxies are back in the pool to prevent data races. |
179 | | */ |
180 | | ~ProxyPool() |
181 | 0 | { |
182 | 0 | std::unique_lock<std::mutex> lock(mtx_); |
183 | 0 | cv_.wait(lock, [&]() |
184 | 0 | { |
185 | 0 | return mask_.all(); |
186 | 0 | }); Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::ReaderProxyData, 4ul>::~ProxyPool()::{lambda()#1}::operator()() const Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::WriterProxyData, 4ul>::~ProxyPool()::{lambda()#1}::operator()() const |
187 | 0 | } Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::ReaderProxyData, 4ul>::~ProxyPool() Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::WriterProxyData, 4ul>::~ProxyPool() |
188 | | |
189 | | /* |
190 | | * Returns the number of proxies in the pool. |
191 | | * @return pool size |
192 | | */ |
193 | | static constexpr std::size_t size() |
194 | | { |
195 | | return N; |
196 | | } |
197 | | |
198 | | /* |
199 | | * Returns the number of proxies available in the pool. |
200 | | * @return available proxies |
201 | | */ |
202 | | std::size_t available() const noexcept |
203 | | { |
204 | | std::lock_guard<std::mutex> _(mtx_); |
205 | | return mask_.count(); |
206 | | } |
207 | | |
208 | | /* |
209 | | * Retrieve an available proxy from the pool. |
210 | | * If not available a wait ensues. |
211 | | * Note deleter is referenced not copied to avoid heap allocations on smart pointer construction |
212 | | * @return unique_ptr referencing the proxy. On destruction the resource is returned. |
213 | | */ |
214 | | std::unique_ptr<Proxy, D&> get() |
215 | 0 | { |
216 | 0 | std::unique_lock<std::mutex> lock(mtx_); |
217 | | |
218 | | // wait for available resources |
219 | 0 | cv_.wait(lock, [&]() |
220 | 0 | { |
221 | 0 | return mask_.any(); |
222 | 0 | }); Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::WriterProxyData, 4ul>::get()::{lambda()#1}::operator()() const Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::ReaderProxyData, 4ul>::get()::{lambda()#1}::operator()() const |
223 | | |
224 | | // find the first available |
225 | 0 | std::size_t idx = 0; |
226 | 0 | while (idx < mask_.size() && !mask_.test(idx)) |
227 | 0 | { |
228 | 0 | ++idx; |
229 | 0 | } |
230 | | |
231 | | // retrieve it |
232 | 0 | mask_.reset(idx); |
233 | 0 | return std::unique_ptr<Proxy, D&>(&heap_[idx], deleter_); |
234 | 0 | } Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::WriterProxyData, 4ul>::get() Unexecuted instantiation: eprosima::ProxyPool<eprosima::fastrtps::rtps::ReaderProxyData, 4ul>::get() |
235 | | |
236 | | }; |
237 | | |
238 | | } // eprosima namespace |
239 | | |
240 | | #endif /* FASTRTPS_UTILS_PROXY_POOL_HPP_ */ |