Coverage Report

Created: 2022-08-24 06:18

/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_ */