Directory: | ./ |
---|---|
File: | pdcom5/src/Process.cpp |
Date: | 2024-12-15 04:08:34 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 109 | 147 | 74.1% |
Branches: | 57 | 144 | 39.6% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /***************************************************************************** | ||
2 | * | ||
3 | * Copyright (C) 2007-2016 Richard Hacker (lerichi at gmx dot net) | ||
4 | * Florian Pose <fp@igh.de> | ||
5 | * | ||
6 | * This file is part of the PdCom library. | ||
7 | * | ||
8 | * The PdCom library is free software: you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU Lesser General Public License as published by | ||
10 | * the Free Software Foundation, either version 3 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * The PdCom library is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
16 | * License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU Lesser General Public License | ||
19 | * along with the PdCom library. If not, see <http://www.gnu.org/licenses/>. | ||
20 | * | ||
21 | *****************************************************************************/ | ||
22 | |||
23 | #include "Process.h" | ||
24 | |||
25 | #include "Debug.h" | ||
26 | #include "Future.h" | ||
27 | #include "IOLayer.h" | ||
28 | #include "ProtocolHandler.h" | ||
29 | #include "Subscription.h" | ||
30 | #include "Variable.h" | ||
31 | #include "msrproto/ProtocolHandler.h" | ||
32 | #include "pdcom5.h" | ||
33 | |||
34 | #include <algorithm> | ||
35 | #include <git_revision_hash.h> | ||
36 | #include <mutex> | ||
37 | |||
38 | #define STR(x) #x | ||
39 | #define QUOTE(x) STR(x) | ||
40 | |||
41 | const char *const PdCom::pdcom_version_code = | ||
42 | QUOTE(PDCOM_MAJOR) "." QUOTE(PDCOM_MINOR) "." QUOTE(PDCOM_RELEASE); | ||
43 | |||
44 | const char *const PdCom::pdcom_full_version = GIT_REV; | ||
45 | |||
46 | using iProcess = PdCom::impl::Process; | ||
47 | |||
48 | namespace PdCom { namespace impl { | ||
49 | ✗ | class PendingSubscription : public PdCom::impl::Subscription | |
50 | { | ||
51 | public: | ||
52 | ✗ | PendingSubscription( | |
53 | std::shared_ptr<const PdCom::impl::Variable> variable, | ||
54 | PdCom::Subscription *This, | ||
55 | PdCom::Subscriber &subscriber, | ||
56 | ✗ | std::shared_ptr<iProcess> process) : | |
57 | ✗ | Subscription(std::move(variable), This, subscriber, process) | |
58 | {} | ||
59 | |||
60 | ✗ | static std::shared_ptr<PendingSubscription> make_and_notify( | |
61 | std::shared_ptr<const PdCom::impl::Variable> variable, | ||
62 | PdCom::Subscription *This, | ||
63 | PdCom::Subscriber &subscriber, | ||
64 | std::shared_ptr<iProcess> process) | ||
65 | { | ||
66 | auto ans = std::make_shared<PendingSubscription>( | ||
67 | ✗ | std::move(variable), This, subscriber, process); | |
68 | |||
69 | ✗ | process->pending_callbacks_.push_back( | |
70 | {ans, PdCom::Subscription::State::Pending}); | ||
71 | ✗ | return ans; | |
72 | } | ||
73 | |||
74 | |||
75 | ✗ | void poll() override { throw PdCom::InvalidSubscription(); } | |
76 | ✗ | const void *getData() const override { throw PdCom::InvalidSubscription(); } | |
77 | }; | ||
78 | }} // namespace PdCom::impl | ||
79 | |||
80 | using PdCom::impl::PendingSubscription; | ||
81 | |||
82 | /////////////////////////////////////////////////////////////////////////// | ||
83 | 159 | iProcess::Process(PdCom::Process *This) : | |
84 | std::enable_shared_from_this<iProcess>(), | ||
85 | PdCom::impl::IOLayer(nullptr), | ||
86 | This(This), | ||
87 |
1/2✓ Branch 4 taken 159 times.
✗ Branch 5 not taken.
|
159 | io(this) |
88 | 159 | {} | |
89 | |||
90 | /////////////////////////////////////////////////////////////////////////// | ||
91 | 119 | void iProcess::reset() | |
92 | { | ||
93 |
1/2✓ Branch 3 taken 119 times.
✗ Branch 4 not taken.
|
238 | std::unique_lock<AsyncDataMutex> lck(async_data_mutex_); |
94 | |||
95 | 119 | io->rxbytes = 0; | |
96 | 119 | io->txbytes = 0; | |
97 | |||
98 | 119 | protocolHandler_.reset(); | |
99 | 119 | } | |
100 | |||
101 | /////////////////////////////////////////////////////////////////////////// | ||
102 | 1143 | void iProcess::asyncData() | |
103 | { | ||
104 |
1/2✓ Branch 3 taken 1143 times.
✗ Branch 4 not taken.
|
2286 | std::unique_lock<AsyncDataMutex> lck(async_data_mutex_); |
105 |
1/2✓ Branch 2 taken 1143 times.
✗ Branch 3 not taken.
|
1143 | pending_callbacks_.flush(); |
106 |
2/2✓ Branch 2 taken 157 times.
✓ Branch 3 taken 986 times.
|
1143 | if (!protocolHandler_) |
107 |
2/4✓ Branch 2 taken 157 times.
✗ Branch 3 not taken.
✓ Branch 9 taken 157 times.
✗ Branch 10 not taken.
|
157 | protocolHandler_.reset(new MsrProto::ProtocolHandler(this, io)); |
108 | |||
109 |
1/2✓ Branch 8 taken 1143 times.
✗ Branch 9 not taken.
|
1143 | protocolHandler_->cancelSubscriptions(); |
110 |
4/4✓ Branch 8 taken 1142 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 17 times.
✓ Branch 11 taken 1125 times.
|
1143 | if (!protocolHandler_->asyncData()) { |
111 | 17 | protocolHandler_.reset(); | |
112 | // first, make all subs invalid | ||
113 | 34 | auto old_subs = std::move(all_subscriptions_); | |
114 |
2/2✓ Branch 5 taken 2 times.
✓ Branch 6 taken 17 times.
|
19 | for (const auto ®istered_s : old_subs) { |
115 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
|
4 | if (const auto sub = registered_s.subscription_.lock()) { |
116 | ✗ | pending_callbacks_.push_back( | |
117 | {sub, PdCom::Subscription::State::Invalid}); | ||
118 | } | ||
119 | } | ||
120 | // give control flow back | ||
121 |
1/2✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | pending_callbacks_.flush(); |
122 | // replace all sub implementations as they are invalid now | ||
123 |
2/2✓ Branch 5 taken 2 times.
✓ Branch 6 taken 17 times.
|
19 | for (const auto ®istered_s : old_subs) { |
124 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
4 | if (const auto sub = registered_s.subscription_.lock()) { |
125 | ✗ | if (!sub->This_) | |
126 | ✗ | continue; | |
127 | ✗ | auto new_sub = std::make_shared<PendingSubscription>( | |
128 | ✗ | nullptr, sub->This_, sub->subscriber_, | |
129 | ✗ | shared_from_this()); | |
130 | ✗ | sub->replaceImpl(new_sub); | |
131 | |||
132 | ✗ | all_subscriptions_.insert( | |
133 | {new_sub, registered_s.path_, registered_s.selector_}); | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | else { | ||
138 |
1/2✓ Branch 8 taken 1125 times.
✗ Branch 9 not taken.
|
1125 | protocolHandler_->cancelSubscriptions(); |
139 | } | ||
140 |
1/2✓ Branch 2 taken 1142 times.
✗ Branch 3 not taken.
|
1142 | pending_callbacks_.flush(); |
141 | 1142 | } | |
142 | |||
143 | |||
144 | 28 | std::shared_ptr<PdCom::impl::Subscription> iProcess::subscribe( | |
145 | PdCom::Subscription *subscription, | ||
146 | const std::string &path, | ||
147 | PdCom::Subscriber &subscriber, | ||
148 | const PdCom::Selector &selector) | ||
149 | { | ||
150 | 28 | std::shared_ptr<PdCom::impl::Subscription> ans; | |
151 |
1/2✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | if (protocolHandler_) |
152 |
1/2✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
|
84 | ans = protocolHandler_->subscribe( |
153 | 84 | subscription, path, subscriber, selector); | |
154 | else | ||
155 | ✗ | ans = PendingSubscription::make_and_notify( | |
156 | ✗ | nullptr, subscription, subscriber, shared_from_this()); | |
157 |
2/4✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
✓ Branch 11 taken 28 times.
✗ Branch 12 not taken.
|
28 | all_subscriptions_.insert({ans, path, selector.impl_}); |
158 | 28 | return ans; | |
159 | } | ||
160 | 56 | std::shared_ptr<PdCom::impl::Subscription> iProcess::subscribe( | |
161 | PdCom::Subscription *subscription, | ||
162 | std::shared_ptr<const PdCom::impl::Variable> var, | ||
163 | PdCom::Subscriber &subscriber, | ||
164 | const PdCom::Selector &selector) | ||
165 | { | ||
166 | 56 | std::shared_ptr<PdCom::impl::Subscription> ans; | |
167 |
1/2✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
|
56 | if (protocolHandler_) |
168 |
1/2✓ Branch 5 taken 56 times.
✗ Branch 6 not taken.
|
168 | ans = protocolHandler_->subscribe( |
169 | 168 | subscription, var, subscriber, selector); | |
170 | else | ||
171 | ✗ | ans = PendingSubscription::make_and_notify( | |
172 | ✗ | nullptr, subscription, subscriber, shared_from_this()); | |
173 |
2/4✓ Branch 7 taken 56 times.
✗ Branch 8 not taken.
✓ Branch 13 taken 56 times.
✗ Branch 14 not taken.
|
56 | all_subscriptions_.insert({ans, var->getPath(), selector.impl_}); |
174 | 56 | return ans; | |
175 | } | ||
176 | |||
177 | 149 | void iProcess::connected() | |
178 | { | ||
179 | 298 | auto old_subs = std::move(all_subscriptions_); | |
180 |
1/2✗ Branch 5 not taken.
✓ Branch 6 taken 149 times.
|
149 | for (const auto ®istered_sub : old_subs) |
181 | ✗ | if (const auto sub = registered_sub.subscription_.lock()) { | |
182 | ✗ | auto new_sub = protocolHandler_->subscribe( | |
183 | ✗ | sub->This_, registered_sub.path_, sub->subscriber_, | |
184 | ✗ | {registered_sub.selector_}); | |
185 | ✗ | sub->replaceImpl(new_sub); | |
186 | ✗ | all_subscriptions_.insert( | |
187 | {new_sub, registered_sub.path_, registered_sub.selector_}); | ||
188 | } | ||
189 |
1/2✓ Branch 24 taken 149 times.
✗ Branch 25 not taken.
|
149 | This->connected(); |
190 | 149 | } | |
191 | |||
192 | using PdCom::impl::Subscription; | ||
193 | |||
194 | 26 | void iProcess::replace( | |
195 | std::shared_ptr<Subscription> const &old_s, | ||
196 | std::shared_ptr<Subscription> const &new_s) | ||
197 | { | ||
198 | 26 | const auto it = std::find_if( | |
199 | 78 | all_subscriptions_.begin(), all_subscriptions_.end(), | |
200 | 130 | [&old_s](const RegisteredSubscription &rs) { | |
201 | 78 | return !rs.subscription_.owner_before(old_s) | |
202 |
2/4✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 5 taken 26 times.
✗ Branch 6 not taken.
|
78 | and !old_s.owner_before(rs.subscription_); |
203 |
1/2✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
|
130 | }); |
204 |
1/2✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
|
26 | if (it != all_subscriptions_.end()) { |
205 |
2/4✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
✓ Branch 13 taken 26 times.
✗ Branch 14 not taken.
|
26 | all_subscriptions_.insert({new_s, it->path_, it->selector_}); |
206 |
1/2✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
|
26 | all_subscriptions_.erase(it); |
207 | } | ||
208 | 26 | } | |
209 | |||
210 | |||
211 | using PdCom::Process; | ||
212 | |||
213 | Process::~Process() = default; | ||
214 | |||
215 |
1/2✓ Branch 9 taken 147 times.
✗ Branch 10 not taken.
|
147 | Process::Process() : pimpl(std::make_shared<PdCom::impl::Process>(this)) |
216 | 147 | {} | |
217 | |||
218 | 12 | Process::Process(std::shared_ptr<iProcess> impl) : pimpl(impl) | |
219 | 12 | {} | |
220 | |||
221 | 14 | std::string Process::name() const | |
222 | { | ||
223 | 14 | return pimpl->protocolHandler().name(); | |
224 | } | ||
225 | |||
226 | 11 | std::string Process::version() const | |
227 | { | ||
228 | 11 | return pimpl->protocolHandler().version(); | |
229 | } | ||
230 | |||
231 | 29 | void Process::setAuthManager(PdCom::Sasl *am) | |
232 | { | ||
233 | 29 | pimpl->setAuthManager(am); | |
234 | 29 | } | |
235 | |||
236 | ✗ | PdCom::Sasl *Process::getAuthManager() const | |
237 | { | ||
238 | ✗ | return pimpl->auth_manager_; | |
239 | } | ||
240 | |||
241 | 127 | void Process::setMessageManager(PdCom::MessageManagerBase *mm) | |
242 | { | ||
243 | 127 | pimpl->setMessageManager(mm); | |
244 | 127 | } | |
245 | |||
246 | 119 | void Process::reset() | |
247 | { | ||
248 | 119 | pimpl->reset(); | |
249 | 119 | } | |
250 | |||
251 | 1143 | void Process::asyncData() | |
252 | { | ||
253 | 1143 | pimpl->asyncData(); | |
254 | 1142 | } | |
255 | |||
256 | 19 | bool Process::list(const std::string &path) | |
257 | { | ||
258 | 19 | return pimpl->protocolHandler().list(path); | |
259 | } | ||
260 | |||
261 | 84 | bool Process::find(const std::string &path) | |
262 | { | ||
263 | 84 | return pimpl->protocolHandler().find(path); | |
264 | } | ||
265 | |||
266 | 6 | void PdCom::Process::getClientStatistics() | |
267 | { | ||
268 | 6 | pimpl->protocolHandler().getClientStatistics(); | |
269 | 6 | } | |
270 | |||
271 | ✗ | void PdCom::Process::clientStatisticsReply(std::vector<PdCom::ClientStatistics>) | |
272 | {} | ||
273 | |||
274 | 4 | void Process::ping() | |
275 | { | ||
276 | 4 | pimpl->protocolHandler().ping(); | |
277 | 4 | } | |
278 | |||
279 | 29 | void Process::broadcast(const std::string &message, const std::string &attr) | |
280 | { | ||
281 | 29 | pimpl->protocolHandler().broadcast(message, attr); | |
282 | 20 | } | |
283 | |||
284 | ✗ | void Process::broadcastReply( | |
285 | const std::string &, | ||
286 | const std::string &, | ||
287 | std::chrono::nanoseconds, | ||
288 | const std::string &) | ||
289 | {} | ||
290 | ✗ | void Process::listReply(std::vector<PdCom::Variable>, std::vector<std::string>) | |
291 | {} | ||
292 | |||
293 | ✗ | void Process::findReply(const PdCom::Variable &) | |
294 | {} | ||
295 | |||
296 | 241 | void Process::callPendingCallbacks() | |
297 | { | ||
298 | 241 | pimpl->pending_callbacks_.flush(); | |
299 |
2/2✓ Branch 6 taken 184 times.
✓ Branch 7 taken 57 times.
|
241 | if (const auto p = pimpl->castProtocolHandler()) |
300 |
1/2✓ Branch 4 taken 184 times.
✗ Branch 5 not taken.
|
184 | if (!pimpl->async_data_mutex_.isLocked()) |
301 | 184 | p->cancelSubscriptions(); | |
302 | 241 | } | |
303 | |||
304 | ✗ | std::vector<Process::SubscriptionInfo> Process::getActiveSubscriptions() const | |
305 | { | ||
306 | ✗ | return pimpl->protocolHandler().getActiveSubscriptions(); | |
307 | } | ||
308 | |||
309 | 2680 | void iProcess::PendingCallbackQueue::flush() | |
310 | { | ||
311 |
2/2✓ Branch 2 taken 137 times.
✓ Branch 3 taken 2543 times.
|
2680 | while (!empty()) { |
312 | 274 | const auto p = front(); | |
313 | 137 | pop_front(); | |
314 |
1/2✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
|
137 | p.execute(); |
315 | } | ||
316 | 2543 | } | |
317 | |||
318 | 8 | PdCom::Variable::PollFuture PdCom::Variable::poll() const | |
319 | { | ||
320 |
2/4✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
|
8 | if (auto impl = pimpl_.lock()) { |
321 |
2/4✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
|
8 | if (const auto process = impl->process.lock()) { |
322 | 8 | auto ans = createFuture< | |
323 | PdCom::Exception const &, VariablePollResult, | ||
324 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
|
16 | std::chrono::nanoseconds>(); |
325 |
2/4✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
|
24 | process->protocolHandler().pollVariable( |
326 | 16 | *impl, std::move(ans.second)); | |
327 | 16 | return std::move(ans.first); | |
328 | } | ||
329 | ✗ | throw ProcessGoneAway(); | |
330 | } | ||
331 | ✗ | throw EmptyVariable(); | |
332 | } | ||
333 |