INSTINCT Code Coverage Report


Directory: src/
File: internal/Node/Node.cpp
Date: 2025-02-07 16:54:41
Exec Total Coverage
Lines: 338 538 62.8%
Functions: 34 53 64.2%
Branches: 369 845 43.7%

Line Branch Exec Source
1 // This file is part of INSTINCT, the INS Toolkit for Integrated
2 // Navigation Concepts and Training by the Institute of Navigation of
3 // the University of Stuttgart, Germany.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9 #include "Node.hpp"
10
11 #include <stdexcept>
12
13 #include "util/StringUtil.hpp"
14 #include "util/Assert.h"
15
16 #include "internal/FlowExecutor.hpp"
17 #include "internal/gui/FlowAnimation.hpp"
18 #include "internal/NodeManager.hpp"
19 namespace nm = NAV::NodeManager;
20 #include "util/Json.hpp"
21 #include "internal/gui/NodeEditorApplication.hpp"
22
23 #include <imgui_node_editor.h>
24 namespace ed = ax::NodeEditor;
25 #ifdef TESTING
26 #include <catch2/catch_test_macros.hpp>
27 #endif
28
29 6394 NAV::Node::Node(std::string name)
30
1/2
✓ Branch 14 taken 6394 times.
✗ Branch 15 not taken.
6394 : name(std::move(name))
31 {
32 LOG_TRACE("{}: called", nameId());
33
2/2
✓ Branch 0 taken 346 times.
✓ Branch 1 taken 6048 times.
6394 if (_autostartWorker)
34 {
35
1/2
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
346 _worker = std::thread(workerThread, this);
36 }
37 6394 }
38
39 12784 NAV::Node::~Node()
40 {
41 LOG_TRACE("{}: called", nameId());
42
43
2/2
✓ Branch 0 taken 344 times.
✓ Branch 1 taken 6048 times.
12784 if (_autostartWorker)
44 {
45 688 _state = State::DoShutdown;
46 688 wakeWorker();
47
48 // // wait for the worker
49 // {
50 // std::unique_lock lk(_workerMutex);
51 // _workerConditionVariable.wait(lk, [&, this] { return _state == State::Shutdown; });
52 // }
53 688 _worker.join();
54 }
55 12784 }
56
57 void NAV::Node::guiConfig() {}
58
59 json NAV::Node::save() const { return {}; }
60
61 53 void NAV::Node::restore(const json& /*j*/) {}
62
63 305 void NAV::Node::restoreAtferLink(const json& /*j*/) {}
64
65 160 bool NAV::Node::initialize()
66 {
67 160 return true;
68 }
69
70 94 void NAV::Node::deinitialize() {}
71
72 324 void NAV::Node::flush() {}
73
74 329 bool NAV::Node::resetNode()
75 {
76 LOG_TRACE("{}: called", nameId());
77
78 329 return initialize();
79 }
80
81 532 bool NAV::Node::onCreateLink(OutputPin& /*startPin*/, InputPin& /*endPin*/)
82 {
83 532 return true;
84 }
85
86 537 void NAV::Node::onDeleteLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) {}
87
88 444 void NAV::Node::afterCreateLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) {}
89
90 511 void NAV::Node::afterDeleteLink(OutputPin& /*startPin*/, InputPin& /*endPin*/) {}
91
92 void NAV::Node::notifyOutputValueChanged(size_t pinIdx, const InsTime& insTime, const std::scoped_lock<std::mutex>& /* guard */)
93 {
94 if (callbacksEnabled && isInitialized())
95 {
96 auto& outputPin = outputPins.at(pinIdx);
97
98 if (!outputPin.isPinLinked()) { return; }
99
100 for (auto& link : outputPin.links)
101 {
102 auto* targetPin = link.getConnectedPin();
103 if (link.connectedNode->isInitialized() && !targetPin->queueBlocked)
104 {
105 outputPin.dataAccessCounter++;
106 link.dataChangeNotification = true;
107 LOG_DATA("{}: Increasing data access counter on output pin '{}'. Value now {}.", nameId(), outputPin.name, outputPin.dataAccessCounter);
108
109 if (nm::showFlowWhenNotifyingValueChange)
110 {
111 FlowAnimation::Add(link.linkId);
112 }
113
114 auto data = std::make_shared<NodeData>();
115 data->insTime = insTime;
116
117 targetPin->queue.push_back(data);
118 }
119 }
120 for (const auto& link : outputPin.links)
121 {
122 auto* targetPin = link.getConnectedPin();
123 if (link.connectedNode->isInitialized() && !targetPin->queueBlocked)
124 {
125 LOG_DATA("{}: Waking up worker of node '{}'. New data on pin '{}'", nameId(), link.connectedNode->nameId(), targetPin->name);
126 link.connectedNode->wakeWorker();
127 }
128 }
129 }
130 }
131
132 145 std::scoped_lock<std::mutex> NAV::Node::requestOutputValueLock(size_t pinIdx)
133 {
134 145 auto& outputPin = outputPins.at(pinIdx);
135 {
136
1/2
✓ Branch 1 taken 145 times.
✗ Branch 2 not taken.
145 std::unique_lock<std::mutex> lk(outputPin.dataAccessMutex);
137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 145 times.
145 if (outputPin.dataAccessCounter > 0)
138 {
139 LOG_DATA("{}: Requesting lock on output pin '{}', {} threads accessing still.", nameId(), outputPin.name, outputPin.dataAccessCounter);
140 outputPin.dataAccessConditionVariable.wait(lk, [&outputPin]() { return outputPin.dataAccessCounter == 0; });
141 LOG_DATA("{}: Lock on output pin '{}' acquired.", nameId(), outputPin.name);
142 }
143 145 }
144 145 return std::scoped_lock(outputPin.dataAccessMutex);
145 }
146
147 void NAV::Node::releaseInputValue(size_t portIndex)
148 {
149 if (OutputPin* outputPin = inputPins.at(portIndex).link.getConnectedPin())
150 {
151 std::scoped_lock<std::mutex> lk(outputPin->dataAccessMutex);
152 if (outputPin->dataAccessCounter > 0)
153 {
154 auto outgoingLink = std::ranges::find_if(outputPin->links, [&](const OutputPin::OutgoingLink& link) {
155 return link.connectedPinId == inputPins.at(portIndex).id;
156 });
157 if (outgoingLink != outputPin->links.end() && outgoingLink->dataChangeNotification)
158 {
159 outgoingLink->dataChangeNotification = false;
160 outputPin->dataAccessCounter--;
161
162 if (outputPin->dataAccessCounter == 0)
163 {
164 LOG_DATA("{}: Notifying node '{}' connected to pin {} that all data is read.", nameId(), outputPin->parentNode->nameId(), outputPin->name);
165 outputPin->dataAccessConditionVariable.notify_all();
166 }
167 }
168 }
169 }
170 }
171
172 365355 void NAV::Node::invokeCallbacks(size_t portIndex, const std::shared_ptr<const NAV::NodeData>& data)
173 {
174
2/2
✓ Branch 0 taken 365340 times.
✓ Branch 1 taken 15 times.
365355 if (callbacksEnabled)
175 {
176
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 365244 times.
365340 if (data == nullptr)
177 {
178 LOG_DEBUG("{}: Tried to invokeCallbacks on pin {} with a nullptr, which is not allowed!!!", nameId(), portIndex);
179 return;
180 }
181
2/2
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 365058 times.
365244 if (data->insTime.empty())
182 {
183 LOG_DATA("{}: Tried to invokeCallbacks on pin {} without a InsTime. The time is mandatory though!!! ", nameId(), portIndex);
184 49 return;
185 }
186
187
3/4
✓ Branch 1 taken 365134 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 543087 times.
✓ Branch 9 taken 365317 times.
908470 for (const auto& link : outputPins.at(portIndex).links)
188 {
189
1/2
✓ Branch 1 taken 543416 times.
✗ Branch 2 not taken.
543031 auto* targetPin = link.getConnectedPin();
190
7/8
✓ Branch 1 taken 543138 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 494691 times.
✓ Branch 4 taken 48447 times.
✓ Branch 5 taken 467123 times.
✓ Branch 6 taken 27568 times.
✓ Branch 7 taken 467132 times.
✓ Branch 8 taken 76006 times.
543416 if (link.connectedNode->isInitialized() && !targetPin->queueBlocked)
191 {
192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 467132 times.
467132 if (NodeManager::showFlowWhenNotifyingValueChange)
193 {
194 FlowAnimation::Add(link.linkId);
195 }
196
197
1/2
✓ Branch 1 taken 466915 times.
✗ Branch 2 not taken.
467132 targetPin->queue.push_back(data);
198 LOG_DATA("{}: Waking up worker of node {}. New data on pin '{}'", nameId(), size_t(link.connectedNode->id), targetPin->name);
199
1/2
✓ Branch 1 taken 467406 times.
✗ Branch 2 not taken.
466915 link.connectedNode->wakeWorker();
200 }
201 }
202 }
203 }
204
205 NAV::InputPin& NAV::Node::inputPinFromId(ax::NodeEditor::PinId pinId)
206 {
207 for (auto& inputPin : inputPins)
208 {
209 if (pinId == inputPin.id) { return inputPin; }
210 }
211
212 throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str());
213 }
214
215 NAV::OutputPin& NAV::Node::outputPinFromId(ax::NodeEditor::PinId pinId)
216 {
217 for (auto& outputPin : outputPins)
218 {
219 if (pinId == outputPin.id) { return outputPin; }
220 }
221
222 throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str());
223 }
224
225 75 size_t NAV::Node::inputPinIndexFromId(ax::NodeEditor::PinId pinId) const
226 {
227
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 for (size_t i = 0; i < inputPins.size(); i++)
228 {
229
2/2
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 79 times.
154 if (pinId == inputPins.at(i).id) { return i; }
230 }
231
232 throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str());
233 }
234
235 size_t NAV::Node::outputPinIndexFromId(ax::NodeEditor::PinId pinId) const
236 {
237 for (size_t i = 0; i < outputPins.size(); i++)
238 {
239 if (pinId == outputPins.at(i).id) { return i; }
240 }
241
242 throw std::runtime_error(fmt::format("{}: The Pin {} is not on this node.", nameId(), size_t(pinId)).c_str());
243 }
244
245 99229 std::string NAV::Node::nameId() const
246 {
247
5/10
✓ Branch 1 taken 99223 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 99196 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 99183 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 99213 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 99177 times.
✗ Branch 14 not taken.
595195 return fmt::format("{} ({})", str::replaceAll_copy(name, "\n", ""), size_t(id));
248 }
249
250 const ImVec2& NAV::Node::getSize() const
251 {
252 return _size;
253 }
254
255 672 std::string NAV::Node::toString(State state)
256 {
257
2/10
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 339 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 340 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
672 switch (state)
258 {
259 case State::Disabled:
260 return "Disabled";
261 case State::Deinitialized:
262 return "Deinitialized";
263 339 case State::DoInitialize:
264
1/2
✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
681 return "DoInitialize";
265 case State::Initializing:
266 return "Initializing";
267 case State::Initialized:
268 return "Initialized";
269 340 case State::DoDeinitialize:
270
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
680 return "DoDeinitialize";
271 case State::Deinitializing:
272 return "Deinitializing";
273 case State::DoShutdown:
274 return "DoShutdown";
275 case State::Shutdown:
276 return "Shutdown";
277 }
278 return "";
279 }
280
281 NAV::Node::State NAV::Node::getState() const
282 {
283 std::scoped_lock lk(_stateMutex);
284 return _state;
285 }
286
287 NAV::Node::Mode NAV::Node::getMode() const
288 {
289 return _mode;
290 }
291
292 507 bool NAV::Node::doInitialize(bool wait)
293 {
294
1/2
✓ Branch 1 taken 507 times.
✗ Branch 2 not taken.
507 std::unique_lock<std::mutex> lk(_stateMutex);
295 LOG_TRACE("{}: Current state = {}", nameId(), toString(_state));
296
297
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 165 times.
✓ Branch 4 taken 342 times.
✗ Branch 5 not taken.
507 switch (_state)
298 {
299 case State::Initialized:
300 lk.unlock();
301 return true;
302 case State::Disabled:
303 case State::DoShutdown:
304 case State::Shutdown:
305 lk.unlock();
306 return false;
307 case State::DoDeinitialize:
308 case State::Deinitializing:
309 if (_reinitialize)
310 {
311 lk.unlock();
312 break;
313 }
314 lk.unlock();
315 return false;
316 165 case State::DoInitialize:
317 case State::Initializing:
318
1/2
✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
165 lk.unlock();
319 165 break;
320 342 case State::Deinitialized:
321 {
322 342 _state = State::DoInitialize;
323
1/2
✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
342 lk.unlock();
324
1/2
✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
342 wakeWorker();
325 342 break;
326 }
327 }
328
329
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 342 times.
507 if (wait)
330 {
331
1/2
✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
165 std::unique_lock lk(_workerMutex);
332
1/2
✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
165 _workerConditionVariable.wait(lk, [&, this] {
333
1/2
✓ Branch 1 taken 356 times.
✗ Branch 2 not taken.
356 std::scoped_lock lks(_stateMutex);
334
4/4
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 164 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 191 times.
712 return _state == State::Initialized || _state == State::Deinitialized;
335 356 });
336
1/2
✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
165 std::scoped_lock lks(_stateMutex);
337 165 return _state == State::Initialized;
338 165 }
339 342 return true;
340 507 }
341
342 bool NAV::Node::doReinitialize(bool wait)
343 {
344 std::unique_lock<std::mutex> lk(_stateMutex);
345 LOG_TRACE("{}: Current state = {}", nameId(), toString(_state));
346
347 switch (_state)
348 {
349 case State::Disabled:
350 case State::DoShutdown:
351 case State::Shutdown:
352 lk.unlock();
353 return false;
354 case State::DoDeinitialize:
355 case State::Deinitializing:
356 _reinitialize = true;
357 lk.unlock();
358 break;
359 case State::DoInitialize:
360 case State::Initializing:
361 lk.unlock();
362 break;
363 case State::Deinitialized:
364 lk.unlock();
365 return doInitialize(wait);
366 case State::Initialized:
367 _state = State::DoDeinitialize;
368 _reinitialize = true;
369 lk.unlock();
370 wakeWorker();
371 break;
372 }
373
374 if (wait)
375 {
376 std::unique_lock lk(_workerMutex);
377 _workerConditionVariable.wait(lk, [&, this] {
378 std::scoped_lock lks(_stateMutex);
379 return _state == State::Initialized || _state == State::Deinitialized;
380 });
381 std::scoped_lock lks(_stateMutex);
382 return _state == State::Initialized;
383 }
384 return true;
385 }
386
387 356 bool NAV::Node::doDeinitialize(bool wait)
388 {
389
1/2
✓ Branch 1 taken 356 times.
✗ Branch 2 not taken.
356 std::unique_lock<std::mutex> lk(_stateMutex);
390 LOG_TRACE("{}: Current state = {}", nameId(), toString(_state));
391
392
3/5
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 340 times.
✗ Branch 4 not taken.
356 switch (_state)
393 {
394 10 case State::Deinitialized:
395
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 lk.unlock();
396 10 return true;
397 6 case State::Disabled:
398 case State::DoShutdown:
399 case State::Shutdown:
400 case State::DoInitialize:
401 case State::Initializing:
402
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 lk.unlock();
403 6 return false;
404 case State::DoDeinitialize:
405 case State::Deinitializing:
406 lk.unlock();
407 break;
408 340 case State::Initialized:
409 {
410 340 _state = State::DoDeinitialize;
411
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 lk.unlock();
412
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 wakeWorker();
413 340 break;
414 }
415 }
416
417
2/2
✓ Branch 0 taken 338 times.
✓ Branch 1 taken 2 times.
340 if (wait)
418 {
419
1/2
✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
338 std::unique_lock lk(_workerMutex);
420
1/2
✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
338 _workerConditionVariable.wait(lk, [&, this] {
421
1/2
✓ Branch 1 taken 676 times.
✗ Branch 2 not taken.
676 std::scoped_lock lks(_stateMutex);
422 676 return _state == State::Deinitialized;
423 676 });
424 338 }
425 340 return true;
426 356 }
427
428 bool NAV::Node::doDisable(bool wait)
429 {
430 std::unique_lock<std::mutex> lk(_stateMutex);
431 LOG_TRACE("{}: Current state = {}", nameId(), toString(_state));
432
433 switch (_state)
434 {
435 case State::Disabled:
436 lk.unlock();
437 return true;
438 case State::DoShutdown:
439 case State::Shutdown:
440 case State::Initializing:
441 lk.unlock();
442 return false;
443 case State::Initialized:
444 case State::DoDeinitialize:
445 case State::Deinitializing:
446 _disable = true;
447 lk.unlock();
448 doDeinitialize();
449 break;
450 case State::DoInitialize:
451 case State::Deinitialized:
452 {
453 _state = State::Disabled;
454 lk.unlock();
455 break;
456 }
457 }
458
459 if (wait)
460 {
461 std::unique_lock lk(_workerMutex);
462 _workerConditionVariable.wait(lk, [&, this] {
463 std::scoped_lock lks(_stateMutex);
464 return _state == State::Deinitialized;
465 });
466 }
467 return true;
468 }
469
470 bool NAV::Node::doEnable()
471 {
472 std::scoped_lock lk(_stateMutex);
473 LOG_TRACE("{}: Current state = {}", nameId(), toString(_state));
474
475 if (_state == State::Disabled)
476 {
477 _state = State::Deinitialized;
478 }
479 return true;
480 }
481
482 468780 void NAV::Node::wakeWorker()
483 {
484 {
485
1/2
✓ Branch 1 taken 468872 times.
✗ Branch 2 not taken.
468780 std::scoped_lock lk(_workerMutex);
486 468872 _workerWakeup = true;
487 468872 }
488 468880 _workerConditionVariable.notify_all();
489 469312 }
490
491 363504 bool NAV::Node::isDisabled() const
492 {
493
1/2
✓ Branch 1 taken 363534 times.
✗ Branch 2 not taken.
363504 std::scoped_lock lk(_stateMutex);
494 363529 return _state == State::Disabled;
495 363534 }
496 1677275 bool NAV::Node::isInitialized() const
497 {
498
1/2
✓ Branch 1 taken 1675088 times.
✗ Branch 2 not taken.
1677275 std::scoped_lock lk(_stateMutex);
499 1674976 return _state == State::Initialized;
500 1675088 }
501 272463 bool NAV::Node::isTransient() const
502 {
503
1/2
✓ Branch 1 taken 272461 times.
✗ Branch 2 not taken.
272463 std::scoped_lock lk(_stateMutex);
504
1/3
✓ Branch 0 taken 272462 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
272461 switch (_state)
505 {
506 272462 case State::Disabled:
507 case State::Initialized:
508 case State::Deinitialized:
509 272462 return false;
510 case State::DoShutdown:
511 case State::Shutdown:
512 case State::Initializing:
513 case State::DoDeinitialize:
514 case State::Deinitializing:
515 case State::DoInitialize:
516 return true;
517 }
518
519 return true;
520 272461 }
521 3 bool NAV::Node::isOnlyRealtime() const
522 {
523 3 return _onlyRealTime;
524 }
525
526 346 void NAV::Node::workerThread(Node* node)
527 {
528 LOG_TRACE("{}: Worker thread started.", node->nameId());
529
530
1/2
✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
346 std::unique_lock<std::mutex> lk(node->_stateMutex);
531
4/6
✓ Branch 1 taken 273474 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 273475 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 273485 times.
✗ Branch 6 not taken.
546953 while ([]() { return true; }() && node->_state != State::Shutdown)
532 {
533
3/4
✓ Branch 1 taken 1028 times.
✓ Branch 2 taken 272464 times.
✓ Branch 4 taken 1028 times.
✗ Branch 5 not taken.
273485 if (lk.owns_lock()) { lk.unlock(); }
534
535
1/2
✓ Branch 1 taken 273462 times.
✗ Branch 2 not taken.
273492 if (std::unique_lock<std::mutex> lock(node->_stateMutex);
536
2/2
✓ Branch 0 taken 344 times.
✓ Branch 1 taken 273118 times.
273462 node->_state == State::DoShutdown)
537 {
538 LOG_TRACE("{}: Worker doing shutdown...", node->nameId());
539 344 node->_state = State::Shutdown;
540
1/2
✓ Branch 1 taken 344 times.
✗ Branch 2 not taken.
344 lock.unlock();
541 344 node->_workerConditionVariable.notify_all();
542 344 break;
543 273462 }
544
1/2
✓ Branch 1 taken 273132 times.
✗ Branch 2 not taken.
273103 if (std::unique_lock<std::mutex> lock(node->_stateMutex);
545
2/2
✓ Branch 0 taken 334 times.
✓ Branch 1 taken 272798 times.
273132 node->_state == State::DoInitialize)
546 {
547 LOG_TRACE("{}: Worker doing initialization...", node->nameId());
548
1/2
✓ Branch 1 taken 332 times.
✗ Branch 2 not taken.
334 lock.unlock();
549
1/2
✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
332 node->workerInitializeNode();
550 LOG_TRACE("{}: Worker finished initialization, notifying all waiting threads (state = {})", node->nameId(), Node::toString(node->_state));
551 342 node->_workerConditionVariable.notify_all();
552
553
1/2
✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
342 lk.lock();
554 342 continue;
555 273140 }
556
1/2
✓ Branch 1 taken 272806 times.
✗ Branch 2 not taken.
272785 if (std::unique_lock<std::mutex> lock(node->_stateMutex);
557
2/2
✓ Branch 0 taken 340 times.
✓ Branch 1 taken 272466 times.
272806 node->_state == State::DoDeinitialize)
558 {
559 LOG_TRACE("{}: Worker doing deinitialization...", node->nameId());
560
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 lock.unlock();
561
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 node->workerDeinitializeNode();
562 LOG_TRACE("{}: Worker finished deinitialization, notifying all waiting threads (state = {})", node->nameId(), Node::toString(node->_state));
563 340 node->_workerConditionVariable.notify_all();
564
565
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 lk.lock();
566 340 continue;
567 272806 }
568
569
2/4
✓ Branch 1 taken 272469 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 272472 times.
✗ Branch 4 not taken.
272469 if (!node->isTransient())
570 {
571 // Wait for data or state change
572 LOG_DATA("{}: Worker going to sleep", node->nameId());
573 272472 bool timeout = false;
574 {
575
1/2
✓ Branch 1 taken 272468 times.
✗ Branch 2 not taken.
272472 std::unique_lock lk(node->_workerMutex);
576
1/2
✓ Branch 1 taken 272410 times.
✗ Branch 2 not taken.
813055 timeout = !node->_workerConditionVariable.wait_for(lk, node->_workerTimeout, [node] { return node->_workerWakeup; });
577 272410 node->_workerWakeup = false;
578 272410 }
579 LOG_DATA("{}: Worker woke up", node->nameId());
580
581
8/10
✓ Branch 1 taken 271881 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 270566 times.
✓ Branch 4 taken 1315 times.
✓ Branch 5 taken 264 times.
✓ Branch 6 taken 270302 times.
✓ Branch 8 taken 551 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 271048 times.
✓ Branch 11 taken 833 times.
271889 if (node->isInitialized() && (node->callbacksEnabled || node->_mode == Node::Mode::REAL_TIME))
582 {
583
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 271047 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
271048 if (timeout && node->callbacksEnabled) // Timeout reached
584 {
585 node->workerTimeoutHandler();
586 }
587
588 // Check input pin for data and trigger callbacks
589
2/4
✓ Branch 1 taken 270260 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 270534 times.
✗ Branch 4 not taken.
271048 if (std::ranges::any_of(node->inputPins, [](const InputPin& inputPin) {
590 269904 return inputPin.isPinLinked();
591 }))
592 {
593
2/4
✓ Branch 1 taken 737442 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 737460 times.
✗ Branch 4 not taken.
737745 while (node->isInitialized())
594 {
595 // -------------------------- Data processing on input non-flow pins -----------------------------
596 737460 bool notifyTriggered = false;
597
2/2
✓ Branch 1 taken 2121677 times.
✓ Branch 2 taken 738376 times.
2860639 for (size_t i = 0; i < node->inputPins.size(); i++)
598 {
599 2121677 auto& inputPin = node->inputPins[i];
600
4/6
✓ Branch 1 taken 817 times.
✓ Branch 2 taken 2122362 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 817 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2123179 times.
2122572 if (inputPin.type != Pin::Type::Flow && !inputPin.queue.empty())
601 {
602 if (auto callback = std::get<InputPin::DataChangedNotifyFunc>(inputPin.callback))
603 {
604 LOG_DATA("{}: Invoking notify callback on input pin '{}'", node->nameId(), inputPin.name);
605 InsTime insTime = inputPin.queue.extract_front()->insTime;
606 #ifdef TESTING
607 for (const auto& watcherCallback : inputPin.watcherCallbacks)
608 {
609 if (auto watcherCall = std::get<InputPin::DataChangedWatcherNotifyFunc>(watcherCallback))
610 {
611 std::invoke(watcherCall, node, insTime, i);
612 }
613 }
614 #endif
615 std::invoke(callback, node, insTime, i);
616 notifyTriggered = true;
617 }
618 }
619 }
620
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 738376 times.
738376 if (notifyTriggered) { continue; }
621
622 // ------------------------------ Process data on input flow pins --------------------------------
623
6/6
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 738113 times.
✓ Branch 3 taken 234 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 738363 times.
✓ Branch 6 taken 13 times.
738376 if (node->callbacksEnabled || node->_mode == Node::Mode::REAL_TIME)
624 {
625 LOG_DATA("{}: Checking for firable input pins", node->nameId());
626
627
2/2
✓ Branch 1 taken 736416 times.
✓ Branch 2 taken 242 times.
738363 if (node->_mode == Mode::POST_PROCESSING)
628 {
629 // Check if all input flow pins have data
630 736416 bool allInputPinsHaveData = !node->inputPins.empty();
631
2/2
✓ Branch 5 taken 2028925 times.
✓ Branch 6 taken 467538 times.
2497945 for (const auto& inputPin : node->inputPins)
632 {
633
9/10
✓ Branch 1 taken 2030262 times.
✓ Branch 2 taken 2212 times.
✓ Branch 3 taken 2030892 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1953466 times.
✓ Branch 6 taken 77426 times.
✓ Branch 8 taken 507307 times.
✓ Branch 9 taken 1446234 times.
✓ Branch 10 taken 507307 times.
✓ Branch 11 taken 1525242 times.
2030361 if (inputPin.type == Pin::Type::Flow && inputPin.neededForTemporalQueueCheck && !inputPin.queueBlocked && inputPin.queue.empty())
634 {
635
1/2
✓ Branch 1 taken 507294 times.
✗ Branch 2 not taken.
507307 if (auto* connectedPin = inputPin.link.getConnectedPin();
636
6/6
✓ Branch 0 taken 506965 times.
✓ Branch 1 taken 329 times.
✓ Branch 3 taken 270823 times.
✓ Branch 4 taken 236119 times.
✓ Branch 5 taken 270825 times.
✓ Branch 6 taken 236446 times.
507294 connectedPin && !connectedPin->noMoreDataAvailable)
637 {
638 270825 allInputPinsHaveData = false;
639 270825 break;
640 }
641 }
642 }
643
2/2
✓ Branch 0 taken 270816 times.
✓ Branch 1 taken 467547 times.
738363 if (!allInputPinsHaveData)
644 {
645 LOG_DATA("{}: Not all pins have data for temporal sorting", node->nameId());
646 271251 break;
647 }
648 LOG_DATA("{}: All pins have data for temporal sorting", node->nameId());
649 }
650
651 // Find pin with the earliest data
652 467789 InsTime earliestTime;
653 467789 size_t earliestInputPinIdx = 0;
654 467789 int earliestInputPinPriority = -1000;
655
2/2
✓ Branch 1 taken 1371370 times.
✓ Branch 2 taken 467710 times.
1839547 for (size_t i = 0; i < node->inputPins.size(); i++)
656 {
657 1371370 auto& inputPin = node->inputPins[i];
658
2/2
✓ Branch 2 taken 1148206 times.
✓ Branch 3 taken 223959 times.
2744928 if (inputPin.type == Pin::Type::Flow && !inputPin.queue.empty()
659
6/6
✓ Branch 0 taken 1372233 times.
✓ Branch 1 taken 435 times.
✓ Branch 3 taken 681309 times.
✓ Branch 4 taken 466580 times.
✓ Branch 5 taken 678769 times.
✓ Branch 6 taken 693735 times.
3426363 && (earliestTime.empty()
660
2/2
✓ Branch 3 taken 469262 times.
✓ Branch 4 taken 211610 times.
681309 || inputPin.queue.front()->insTime < earliestTime
661
4/4
✓ Branch 3 taken 392570 times.
✓ Branch 4 taken 77350 times.
✓ Branch 5 taken 526 times.
✓ Branch 6 taken 392044 times.
469262 || (inputPin.queue.front()->insTime == earliestTime && inputPin.priority > earliestInputPinPriority)))
662 {
663 678769 earliestTime = inputPin.queue.front()->insTime;
664 678023 earliestInputPinIdx = i;
665 678023 earliestInputPinPriority = inputPin.priority;
666 }
667 }
668
2/2
✓ Branch 0 taken 437 times.
✓ Branch 1 taken 467273 times.
467710 if (earliestInputPinPriority == -1000) { break; }
669
670 467273 auto& inputPin = node->inputPins[earliestInputPinIdx];
671
5/8
✓ Branch 0 taken 467262 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 467306 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 467307 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 467309 times.
✗ Branch 8 not taken.
467263 if (inputPin.firable && inputPin.firable(node, inputPin))
672 {
673
2/4
✓ Branch 1 taken 467174 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 467192 times.
✗ Branch 4 not taken.
467309 if (auto callback = std::get<InputPin::FlowFirableCallbackFunc>(inputPin.callback))
674 {
675 LOG_DATA("{}: Invoking callback on input pin '{}'", node->nameId(), inputPin.name);
676 #ifdef TESTING
677
2/2
✓ Branch 5 taken 63639 times.
✓ Branch 6 taken 467125 times.
530834 for (const auto& watcherCallback : inputPin.watcherCallbacks)
678 {
679
3/6
✓ Branch 1 taken 63640 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 63642 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 63642 times.
✗ Branch 8 not taken.
63639 if (auto watcherCall = std::get<InputPin::FlowFirableWatcherCallbackFunc>(watcherCallback))
680 {
681
1/2
✓ Branch 1 taken 63642 times.
✗ Branch 2 not taken.
63642 std::invoke(watcherCall, node, inputPin.queue, earliestInputPinIdx);
682 63642 }
683 }
684 #endif
685
1/2
✓ Branch 1 taken 467282 times.
✗ Branch 2 not taken.
467125 std::invoke(callback, node, inputPin.queue, earliestInputPinIdx);
686 }
687 }
688 else if (inputPin.dropQueueIfNotFirable)
689 {
690 LOG_DATA("{}: Dropping message on input pin '{}'", node->nameId(), inputPin.name);
691 inputPin.queue.pop_front();
692 }
693 else
694 {
695 LOG_DATA("{}: Skipping message on input pin '{}'", node->nameId(), inputPin.name);
696 break; // Do not drop an item, but put the worker to sleep
697 }
698 }
699 else
700 {
701 13 break;
702 }
703 }
704 }
705
706 // Post-processing (FileReader/Simulator)
707
2/2
✓ Branch 1 taken 120 times.
✓ Branch 2 taken 271283 times.
270972 if (!node->pollEvents.empty())
708 {
709 120 std::multimap<InsTime, std::pair<OutputPin*, size_t>>::iterator it;
710
7/10
✓ Branch 3 taken 120789 times.
✓ Branch 4 taken 10 times.
✓ Branch 6 taken 120792 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 120792 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 120792 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 120789 times.
✓ Branch 13 taken 13 times.
120808 while (it = node->pollEvents.begin(), it != node->pollEvents.end() && node->isInitialized() && node->callbacksEnabled)
711 {
712 120789 OutputPin* outputPin = it->second.first;
713 120785 size_t outputPinIdx = it->second.second;
714 120790 Node* node = outputPin->parentNode;
715
716
2/2
✓ Branch 1 taken 52994 times.
✓ Branch 2 taken 67799 times.
120790 if (std::holds_alternative<OutputPin::PollDataFunc>(outputPin->data))
717 {
718 52994 auto* callback = std::get_if<OutputPin::PollDataFunc>(&outputPin->data);
719
2/4
✓ Branch 0 taken 52987 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52989 times.
✗ Branch 3 not taken.
52987 if (callback != nullptr && *callback != nullptr)
720 {
721 LOG_DATA("{}: Polling data from output pin '{}'", node->nameId(), str::replaceAll_copy(outputPin->name, "\n", ""));
722
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 52989 times.
✓ Branch 3 taken 52994 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 110 times.
✓ Branch 8 taken 52889 times.
52989 if ((node->**callback)() == nullptr)
723 {
724
1/2
✓ Branch 1 taken 110 times.
✗ Branch 2 not taken.
110 node->pollEvents.erase(it); // Delete the event if no more data on this pin
725 110 break;
726 }
727 }
728 }
729
1/2
✓ Branch 1 taken 67800 times.
✗ Branch 2 not taken.
67799 else if (std::holds_alternative<OutputPin::PeekPollDataFunc>(outputPin->data))
730 {
731 67800 auto* callback = std::get_if<OutputPin::PeekPollDataFunc>(&outputPin->data);
732
3/4
✓ Branch 0 taken 67800 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67798 times.
✓ Branch 3 taken 2 times.
67798 if (callback != nullptr && *callback != nullptr)
733 {
734
1/2
✓ Branch 2 taken 67798 times.
✗ Branch 3 not taken.
67798 if (!it->first.empty())
735 {
736 LOG_DATA("{}: Polling data from output pin '{}'", node->nameId(), str::replaceAll_copy(outputPin->name, "\n", ""));
737 // Trigger the already peeked observation and invoke it's callbacks (peek = false)
738
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 67798 times.
✓ Branch 3 taken 67801 times.
✗ Branch 4 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 67800 times.
67798 if ((node->**callback)(outputPinIdx, false) == nullptr)
739 {
740 LOG_ERROR("{}: {} could not poll its observation despite being able to peek it.", node->nameId(), outputPin->name);
741 }
742 }
743
744 // Check if data available (peek = true)
745
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 67800 times.
✓ Branch 3 taken 67804 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 67779 times.
✓ Branch 7 taken 20 times.
67800 if (auto obs = (node->**callback)(outputPinIdx, true))
746 {
747 // Check if data has a time
748
1/2
✓ Branch 2 taken 67776 times.
✗ Branch 3 not taken.
67779 if (!obs->insTime.empty())
749 {
750
1/2
✓ Branch 4 taken 67779 times.
✗ Branch 5 not taken.
67776 node->pollEvents.insert(std::make_pair(obs->insTime, std::make_pair(outputPin, outputPinIdx)));
751 }
752 else // If no time, call the object and remove it
753 {
754 (node->**callback)(outputPinIdx, false);
755 continue; // Do not erase the iterator, because this pin needs to be called again
756 }
757 }
758 else // nullptr -> no more data incoming on this pin
759 {
760 LOG_TRACE("{}: Output Pin finished: {}", node->nameId(), outputPin->name);
761 20 outputPin->noMoreDataAvailable = true;
762
2/2
✓ Branch 5 taken 27 times.
✓ Branch 6 taken 20 times.
47 for (auto& link : outputPin->links)
763 {
764
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 link.connectedNode->wakeWorker();
765 }
766 67799 }
767 67802 }
768 else
769 {
770 LOG_ERROR("{} - {}: Callback is not valid anymore", node->nameId(), size_t(outputPin->id));
771 }
772
1/2
✓ Branch 1 taken 67802 times.
✗ Branch 2 not taken.
67802 node->pollEvents.erase(it);
773 }
774 }
775
776
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
123 if (node->pollEvents.empty())
777 {
778 LOG_TRACE("{}: Finished polling all pins.", node->nameId());
779
780 120 node->callbacksEnabled = false;
781
2/2
✓ Branch 5 taken 136 times.
✓ Branch 6 taken 120 times.
256 for (auto& outputPin : node->outputPins)
782 {
783
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 26 times.
136 if (!outputPin.noMoreDataAvailable)
784 {
785 LOG_TRACE("{}: Output Pin finished: {}", node->nameId(), outputPin.name);
786 110 outputPin.noMoreDataAvailable = true;
787
2/2
✓ Branch 5 taken 112 times.
✓ Branch 6 taken 110 times.
222 for (auto& link : outputPin.links)
788 {
789
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
112 link.connectedNode->wakeWorker();
790 }
791 }
792 }
793 120 node->_mode = Node::Mode::REAL_TIME;
794
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 FlowExecutor::deregisterNode(node);
795 }
796 }
797 }
798
799 // Check if node finished
800
2/2
✓ Branch 1 taken 271024 times.
✓ Branch 2 taken 1393 times.
272236 if (node->_mode == Mode::POST_PROCESSING)
801 {
802
3/4
✓ Branch 1 taken 271063 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 220 times.
✓ Branch 4 taken 270843 times.
271024 if (std::ranges::all_of(node->inputPins, [](const InputPin& inputPin) {
803
6/8
✓ Branch 2 taken 361516 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 361452 times.
✓ Branch 5 taken 64 times.
✓ Branch 7 taken 361465 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 271089 times.
✓ Branch 10 taken 90376 times.
1084589 return inputPin.type != Pin::Type::Flow || !inputPin.isPinLinked() || inputPin.link.connectedNode->isDisabled()
804
3/4
✓ Branch 1 taken 271101 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 271095 times.
✓ Branch 5 taken 9 times.
271089 || !inputPin.link.getConnectedPin()->blocksConnectedNodeFromFinishing
805
7/8
✓ Branch 0 taken 361509 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 153641 times.
✓ Branch 4 taken 117447 times.
✓ Branch 6 taken 153663 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 259 times.
✓ Branch 10 taken 153404 times.
1084628 || (inputPin.queue.empty() && inputPin.link.getConnectedPin()->noMoreDataAvailable);
806 }))
807 {
808 LOG_TRACE("{}: Node finished", node->nameId());
809 220 node->callbacksEnabled = false;
810
2/2
✓ Branch 5 taken 130 times.
✓ Branch 6 taken 220 times.
350 for (auto& outputPin : node->outputPins)
811 {
812 LOG_TRACE("{}: Output Pin finished: {}", node->nameId(), outputPin.name);
813 130 outputPin.noMoreDataAvailable = true;
814
2/2
✓ Branch 5 taken 127 times.
✓ Branch 6 taken 130 times.
257 for (auto& link : outputPin.links)
815 {
816
1/2
✓ Branch 1 taken 127 times.
✗ Branch 2 not taken.
127 link.connectedNode->wakeWorker();
817 }
818 }
819 220 node->_mode = Node::Mode::REAL_TIME;
820
1/2
✓ Branch 1 taken 218 times.
✗ Branch 2 not taken.
219 FlowExecutor::deregisterNode(node);
821 }
822 }
823 }
824 }
825
826 LOG_TRACE("{}: Worker thread ended.", node->nameId());
827 331 }
828
829 331 bool NAV::Node::workerInitializeNode()
830 {
831 LOG_TRACE("{}: called", nameId());
832 {
833
1/2
✓ Branch 1 taken 333 times.
✗ Branch 2 not taken.
331 std::scoped_lock lk(_stateMutex);
834
6/14
✓ Branch 0 taken 333 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 339 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 341 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 341 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 339 times.
✓ Branch 14 taken 2 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
675 INS_ASSERT_USER_ERROR(_state == State::DoInitialize, fmt::format("Worker can only initialize the node if the state is set to DoInitialize, but it is {}.", toString(_state)).c_str());
835 342 _state = Node::State::Initializing;
836 342 }
837 340 _mode = Node::Mode::REAL_TIME;
838
839
3/6
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 342 times.
✗ Branch 9 not taken.
339 LOG_DEBUG("{}: Initializing Node", nameId());
840
841 // Initialize Nodes connected to the input pins
842
2/2
✓ Branch 5 taken 270 times.
✓ Branch 6 taken 342 times.
612 for (const auto& inputPin : inputPins)
843 {
844
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 260 times.
269 if (inputPin.type != Pin::Type::Flow)
845 {
846
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (Node* connectedNode = inputPin.link.connectedNode)
847 {
848
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
10 if (!connectedNode->isInitialized())
849 {
850
5/10
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 10 times.
✗ Branch 15 not taken.
10 LOG_DEBUG("{}: Initializing connected Node '{}' on input Pin {}", nameId(), connectedNode->nameId(), size_t(inputPin.id));
851
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 if (!connectedNode->doInitialize(true))
852 {
853 LOG_ERROR("{}: Could not initialize connected node {}", nameId(), connectedNode->nameId());
854 std::scoped_lock lk(_stateMutex);
855 if (_state == State::Initializing)
856 {
857 _state = Node::State::Deinitialized;
858 }
859 return false;
860 }
861 }
862 }
863 }
864 }
865
866 342 _reinitialize = false;
867
868 // Initialize the node itself
869 LOG_TRACE("{}: calling initialize()", nameId());
870 342 bool initSucceeded = false;
871 {
872
1/2
✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
342 std::scoped_lock<std::mutex> guard(_configWindowMutex);
873
1/2
✓ Branch 1 taken 342 times.
✗ Branch 2 not taken.
342 initSucceeded = initialize();
874 342 }
875
2/2
✓ Branch 0 taken 340 times.
✓ Branch 1 taken 2 times.
342 if (initSucceeded)
876 {
877 LOG_TRACE("{}: initialize() was successful", nameId());
878
879
2/2
✓ Branch 4 taken 270 times.
✓ Branch 5 taken 340 times.
610 for (auto& inputPin : inputPins)
880 {
881 270 inputPin.queue.clear();
882 270 inputPin.queueBlocked = false;
883 }
884
885 340 pollEvents.clear();
886 LOG_TRACE("{}: calling resetNode()", nameId());
887 {
888
1/2
✓ Branch 1 taken 341 times.
✗ Branch 2 not taken.
341 std::scoped_lock<std::mutex> guard(_configWindowMutex);
889
1/2
✓ Branch 1 taken 341 times.
✗ Branch 2 not taken.
341 resetNode();
890 341 }
891 LOG_TRACE("{}: resetNode() was successful", nameId());
892
2/2
✓ Branch 5 taken 266 times.
✓ Branch 6 taken 341 times.
607 for (auto& outputPin : outputPins)
893 {
894 266 outputPin.noMoreDataAvailable = true;
895
2/2
✓ Branch 5 taken 266 times.
✓ Branch 6 taken 266 times.
532 for (auto& link : outputPin.links)
896 {
897 LOG_TRACE("{}: Waking connected node '{}'", nameId(), link.connectedNode->nameId());
898
1/2
✓ Branch 1 taken 266 times.
✗ Branch 2 not taken.
266 link.connectedNode->wakeWorker();
899 }
900 }
901
902
1/2
✓ Branch 1 taken 341 times.
✗ Branch 2 not taken.
341 std::scoped_lock lk(_stateMutex);
903
1/2
✓ Branch 0 taken 341 times.
✗ Branch 1 not taken.
341 if (_state == State::Initializing)
904 {
905 341 _state = Node::State::Initialized;
906 }
907 341 return true;
908 341 }
909
910 LOG_TRACE("{}: initialize() failed", nameId());
911
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 std::scoped_lock lk(_stateMutex);
912
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (_state == State::Initializing)
913 {
914 1 _state = Node::State::Deinitialized;
915 }
916 1 return false;
917 1 }
918
919 340 bool NAV::Node::workerDeinitializeNode()
920 {
921 LOG_TRACE("{}: called", nameId());
922 {
923
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 std::scoped_lock lk(_stateMutex);
924
5/14
✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 340 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 340 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 340 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 340 times.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
680 INS_ASSERT_USER_ERROR(_state == State::DoDeinitialize, fmt::format("Worker can only deinitialize the node if the state is set to DoDeinitialize, but it is {}.", toString(_state)).c_str());
925 {
926 340 _state = Node::State::Deinitializing;
927 }
928 340 }
929
3/6
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 340 times.
✗ Branch 9 not taken.
340 LOG_DEBUG("{}: Deinitializing Node", nameId());
930
931 340 callbacksEnabled = false;
932
933 // Re-/Deinitialize Nodes connected to the output pins
934
2/2
✓ Branch 5 taken 266 times.
✓ Branch 6 taken 340 times.
606 for (const auto& outputPin : outputPins)
935 {
936
2/2
✓ Branch 1 taken 49 times.
✓ Branch 2 taken 217 times.
266 if (outputPin.type != Pin::Type::Flow)
937 {
938
2/2
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 49 times.
53 for (const auto& link : outputPin.links)
939 {
940
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
4 if (link.connectedNode->isInitialized())
941 {
942
6/12
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
2 LOG_DEBUG("{}: {} connected Node '{}' on output Pin {}", nameId(),
943 _reinitialize ? "Reinitializing" : "Deinitializing", link.connectedNode->nameId(), size_t(outputPin.id));
944
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 if (_reinitialize) { link.connectedNode->doReinitialize(); }
945
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 else { link.connectedNode->doDeinitialize(); }
946 }
947 }
948 }
949 }
950
951 // Deinitialize the node itself
952 {
953
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 std::scoped_lock<std::mutex> guard(_configWindowMutex);
954
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 deinitialize();
955 340 }
956
957
1/2
✓ Branch 1 taken 340 times.
✗ Branch 2 not taken.
340 std::scoped_lock lk(_stateMutex);
958
1/2
✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
340 if (_state == State::Deinitializing)
959 {
960
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 340 times.
340 if (_disable)
961 {
962 _state = State::Disabled;
963 }
964
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 340 times.
340 else if (_reinitialize)
965 {
966 _state = State::DoInitialize;
967 }
968 else
969 {
970 340 _state = State::Deinitialized;
971 }
972 }
973
974 340 return true;
975 340 }
976
977 void NAV::Node::workerTimeoutHandler()
978 {
979 LOG_TRACE("{}: called", nameId());
980 }
981
982 void NAV::to_json(json& j, const Node& node)
983 {
984 ImVec2 realSize = ed::GetNodeSize(node.id);
985 realSize.x -= 16;
986 realSize.y -= 38.0F;
987 j = json{
988 { "id", size_t(node.id) },
989 { "type", node.type() },
990 { "kind", std::string(node.kind) },
991 { "name", node.name },
992 { "size", node._size.x == 0 && node._size.y == 0 ? node._size : realSize },
993 { "pos", ed::GetNodePosition(node.id) },
994 { "enabled", !node.isDisabled() },
995 { "inputPins", node.inputPins },
996 { "outputPins", node.outputPins },
997 };
998 }
999 692 void NAV::from_json(const json& j, Node& node)
1000 {
1001
3/6
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 692 times.
✗ Branch 8 not taken.
692 node.id = j.at("id").get<size_t>();
1002
1/2
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
692 if (j.contains("kind"))
1003 {
1004
3/6
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 692 times.
✗ Branch 8 not taken.
692 node.kind = Node::Kind(j.at("kind").get<std::string>());
1005 }
1006
1/2
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
692 if (j.contains("name"))
1007 {
1008 692 j.at("name").get_to(node.name);
1009 }
1010
1/2
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
692 if (j.contains("size"))
1011 {
1012 692 j.at("size").get_to(node._size);
1013
6/8
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 686 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 686 times.
692 if (node.kind == Node::Kind::GroupBox && gui::NodeEditorApplication::isUsingBigDefaultFont())
1014 {
1015 6 node._size.y -= 20;
1016 }
1017 }
1018
1/2
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
692 if (j.contains("enabled"))
1019 {
1020 692 bool enabled = j.at("enabled").get<bool>();
1021
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 690 times.
692 if (!enabled)
1022 {
1023
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 std::scoped_lock lk(node._stateMutex);
1024 2 node._state = Node::State::Disabled;
1025 2 }
1026 }
1027
1028
1/2
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
692 if (j.contains("inputPins"))
1029 {
1030
2/4
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
692 auto inputPins = j.at("inputPins").get<std::vector<InputPin>>();
1031
2/2
✓ Branch 1 taken 524 times.
✓ Branch 2 taken 646 times.
1170 for (size_t i = 0; i < inputPins.size(); ++i)
1032 {
1033
2/2
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 478 times.
524 if (node.inputPins.size() <= i)
1034 {
1035 46 break;
1036 }
1037
4/8
✓ Branch 1 taken 478 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 478 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 478 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 478 times.
✗ Branch 11 not taken.
478 j.at("inputPins").at(i).get_to(node.inputPins.at(i));
1038 }
1039 692 }
1040
1041
1/2
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
692 if (j.contains("outputPins"))
1042 {
1043
2/4
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
692 auto outputPins = j.at("outputPins").get<std::vector<OutputPin>>();
1044
2/2
✓ Branch 1 taken 533 times.
✓ Branch 2 taken 690 times.
1223 for (size_t i = 0; i < outputPins.size(); ++i)
1045 {
1046
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 531 times.
533 if (node.outputPins.size() <= i)
1047 {
1048 2 break;
1049 }
1050
4/8
✓ Branch 1 taken 531 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 531 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 531 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 531 times.
✗ Branch 11 not taken.
531 j.at("outputPins").at(i).get_to(node.outputPins.at(i));
1051 }
1052 692 }
1053 692 }
1054